我需要在数据库中写一行,无论它是否已经存在.在使用NHibernate之前,这是通过存储过程完成的.该过程将尝试更新,如果没有修改行,它将回退到插入.这很好用,因为应用程序不关心记录是否存在.
使用NHibernate,我发现的解决方案需要加载实体并对其进行修改,或删除实体以便插入新实体.如果记录已经存在,应用程序必须关心.有办法吗?
该对象具有关键字作为分配的ID,并且是表中的主键.
据我所知,SaveOrUpdate()将根据Id调用Save()或Update()方法.使用指定的ID,这将不起作用,因为id不是未保存的值.但是,版本或时间戳字段可以用作指示符.实际上,这是不相关的,因为这只反映了内存中的对象是否与数据库中的记录相关联; 它不表示数据库中是否存在记录.
如果分配的id确实是问题的原因,我可以使用生成的id而不是关键字作为主键.这将避免NHibernate插入/更新问题,因为它实际上总是插入.但是,我仍然需要防止重复的关键字.使用关键字列上的唯一索引,即使主键不同,它仍会为重复关键字抛出异常.
也许问题不在于NHibernate,而在于它的建模方式.与应用程序的其他区域不同,这是以数据为中心而非以对象为中心的.NHibernate很容易读/写并消除了存储过程.但是,在不考虑现有值的情况下简单编写的愿望并不适合对象的身份模型的模型.有没有更好的方法来解决这个问题?
我正在使用
public IListGetByExample (T exampleInstance) { return _session.CreateCriteria(typeof(T)) .Add(Example.Create(exampleInstance)) .List (); } public void InsertOrUpdate (T target) { ITransaction transaction = _session.BeginTransaction(); try { var res=GetByExample (target); if( res!=null && res.Count>0 ) _session.SaveOrUpdate(target); else _session.Save(target); transaction.Commit(); } catch (Exception) { transaction.Rollback(); throw; } finally { transaction.Dispose(); } }
但FindByExample方法返回所有对象,而不是具有确切ID的对象,你建议什么?因为我只有对象作为参数我无法访问其特定的ID字段,所以我不能使用session.get(Object.class(), id);
通常,NHibernate可以依赖unsaved-value来确定它是应该插入还是创建实体.但是,由于您要分配ID,因此NHibernate看起来您的实体已经被持久化了.因此,您需要依赖对对象进行版本控制,让NHibernate知道它是一个新对象.有关如何对实体进行版本化,请参阅以下链接:
http://web.archive.org/web/20090831032934/http://devlicio.us/blogs/mike_nichols/archive/2008/07/29/when-flushing-goes-bad-assigned-ids-in-nhibernate. ASPX