拥有NHibernate实体:
public class Employee
{
public virtual int Id { get; set; }
public virtual int Idc { get; set; }
public virtual int Ide { get; set; }
.
. other properties
.
}
将Id映射为:
<id name="Id" unsaved-value="0">
<generator class="sequence">
<param name="sequence">employee_id_seq</param>
</generator>
</id>
如果我填充除了Id之外的新员工的所有属性,然后调用session.Merge()
,它只会创建另一行,其所有属性都与除Id之外的原始行相同,而不是与现有员工合并。
是否可以在与这些属性对应的行上进行数据库级别的更新?
Idc
+ Ide
一起是唯一的,因此应该可以识别要合并的行。
感谢您的帮助!
答案 0 :(得分:1)
NHibernate会话为所有当前加载(持久化)的对象维护identity map。身份映射使用实体ID作为密钥。在您的情况下,Id
是一个简单的int
值,因为对于新创建的对象,它等于0
(默认情况下),session.Merge()
找不到匹配的持久性会话中的实体。而是将新行添加到数据库。
阅读Ayende关于cross-session operations的帖子,以获得更深入的解释。
在其他情况下,如果您希望拥有不同的实体相等概念,则可以覆盖实体的Equals()
和GetHashCode()
方法 - 即比较所有属性,但我担心,在这种情况下,它不会帮助你。
仅供参考,以下是有关Equals()
和GetHashCode()
用法的一些链接:
Is there a sample why Equals/GetHashCode should be overwritten in NHibernate?
NHibernate: Reasons for overriding Equals and GetHashCode
修改强>
在数据库级别更新行有两个选项:
你可以NHibernate update query做这些事情:
Employee emp; // = your new employee instance
session.CreateQuery(
"update Employee set Property1 = :property1, ... " +
"where Idc = :idc, Ide = :ide")
.SetParameter("idc", emp.Idc)
.SetParameter("ide", emp.Ide)
.SetParameter("property1", emp.Property1)
// other properties
.ExecuteUpdate();
此外,您可以使用本机SQL执行此操作:session.CreateSQLQuery("...").ExecuteUpdate();
或者您可以先加载实体,更新其属性然后保存:
Employee emp; // = your new employee instance
Employee oldEmployee = session.Query<Employee>()
.Where(x => x.Idc == emp.Idc)
.Where(x => x.Ide == emp.Ide)
.Single();
oldEmployee.Property1 = emp.Property1;
oldEmployee.Property2 = emp.Property2;
// other properties
session.SaveOrUpdate(oldEmployee);