【问题标题】:How to use ISession.Merge with a serial Id?如何使用带有序列号的 ISession.Merge?
【发布时间】:2012-07-26 13:18:29
【问题描述】:

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

感谢您的帮助!

【问题讨论】:

    标签: c# .net nhibernate


    【解决方案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);
      

    【讨论】:

    • +1 谢谢,您的回答解释了为什么不填充 ID 就无法完成,但并没有给出解决方案,所以我还不能接受
    • @RăzvanPanda 我用两种可能的解决方案编辑了我的答案。
    猜你喜欢
    • 1970-01-01
    • 2014-05-18
    • 1970-01-01
    • 1970-01-01
    • 2013-07-01
    • 1970-01-01
    • 2019-07-26
    • 1970-01-01
    • 2021-12-05
    相关资源
    最近更新 更多