如何使用序列ID的ISession.Merge?

时间:2012-07-26 13:18:29

标签: c# .net nhibernate

拥有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一起是唯一的,因此应该可以识别要合并的行。

感谢您的帮助!

1 个答案:

答案 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

修改

在数据库级别更新行有两个选项:

  1. 你可以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();

  2. 或者您可以先加载实体,更新其属性然后保存:

    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);