0

拥有 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 之外的新 Employee 的所有属性,然后调用session.Merge()它只是创建另一行,其所有属性都与除 Id 之外的原始行相同,而不是与现有员工合并。

是否可以在与这些属性对应的行上进行数据库级别的更新? Idc+Ide一起是唯一的,因此应该可以识别要合并的行。

谢谢你的帮助!

4

1 回答 1

1

NHibernate 会话为所有当前加载(持久)的对象维护一个身份映射。身份映射使用实体 id 作为键。在您的情况下,您Id是一个简单的int值,并且由于它等于0(默认情况下)新创建的对象,session.Merge()因此无法在会话中找到匹配的持久实体。相反,一个新行被添加到数据库中。

阅读 Ayende 关于跨会话操作的文章以获得更深入的解释。

在其他情况下,如果您希望拥有不同的实体平等概念,您将覆盖您的实体Equals()GetHashCode()方法 - 即比较所有属性,但恐怕在这种情况下它不会帮助您。

仅供参考,这里有一些关于Equals()GetHashCode()用法的链接:
Is there a sample why Equals/GetHashCode should be overwritten in NHibernate?
NHibernate:重写 Equals 和 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);
    
于 2012-07-26T13:46:12.377 回答