为什么NHibernate先删除,然后在select上插入复合元素?

为什么NHibernate先删除,然后在select上插入复合元素?,nhibernate,Nhibernate,有人能给我解释一下NHibernate是如何处理复合元素的吗 我有这样的课程 public class Blog { public virtual int Id { get; private set; } public virtual ISet<Comment> Comments { get; set; } } public class Comment { pu

有人能给我解释一下NHibernate是如何处理复合元素的吗

我有这样的课程

public class Blog
{
    public virtual int Id
    {
        get;
        private set;
    }

    public virtual ISet<Comment> Comments
    {
        get;
        set;
    }
}

public class Comment
{
    public virtual string CommentText
    {
        get;
        set;
    }

    public virtual DateTime Date
    {
        get;
        set;
    }
}
<class name="Blog" table="blog">
    <id name="Id" column="id" unsaved-value="0">
      <generator class="hilo"/>
    </id>

    <set name="Comments" table="blog_comments">
      <key column="blog_id" />
      <composite-element class="Comment">
        <property name="CommentText" column="comment" not-null="true" />
        <property name="Date" column="date" not-null="true" />
      </composite-element>
    </set>

  </class>

using (ITransaction transaction = session.BeginTransaction())
{
    Blog blog = session.CreateCriteria(typeof(Blog))
                  .SetFetchMode("Comments", FetchMode.Eager)
                  .Add(Expression.IdEq(2345))            
                  .UniqueResult();

    transaction.Commit();
}

NHibernate发出一个带有连接的select以获取包含帖子的博客,但随后删除所有评论,然后插入评论!为什么要这样做?如果我不使用事务,那么它将只执行select,而不是像我预期的那样执行DELETE和INSERT。我错过了什么?我使用的是NHibernate2.0,我的问题是,如果您只需要进行选择,为什么要提交?我认为它删除所有注释的原因是,当您对事务调用commit时,blog对象及其关联的注释会缓存在用于创建事务的会话中。调用提交时,会导致保存会话中的所有对象,从而导致将其保存回数据库。我不清楚为什么要删除注释,但保存对象是正确的行为

我还:

NHibernate正在删除我的整个 收集并重新创建它 更新表格的步骤。

这通常发生在NHibernate时 无法确定更改了哪些项目 收藏中。常见的原因有:

  • 用新集合实例完全替换持久集合
  • 将手动构造的对象传递给NHibernate并对其调用Update
  • 序列化/反序列化持久集合显然也会导致此问题
  • 使用reverse=“false”更新a”-在这种情况下,NHibernate无法构造SQL来更新单个集合项
因此,为了避免出现问题:

  • 将从NHibernate获得的同一个集合实例传递回它(不一定在同一个会话中)
  • 尝试使用其他集合而不是(或),或
  • 请尝试对使用reverse=“true”属性

我认为您需要在注释中重写Equals()和GetHashCode()。NHibernate没有实体相等的ID,因此您必须定义如何使一个注释实体等于另一个注释

可能是错的:)


编辑

从(8.2)

注意:如果定义复合元素的ISet,正确实现Equals()和GetHashCode()是非常重要的

以及(4.3)中实现Equals/GetHashCode的示例


我认为commit只会更新已经更改的实体,因为没有一个实体会更新,为什么它会尝试更新任何东西?我也读了这一页,我同意你不应该使用隐式事务,我只是不清楚如果没有任何更改,为什么你会提交事务。无论如何,我喜欢这个问题,而且答案非常翔实-1因为您应该始终有显式事务,如果没有提交,您会收到警告。谢谢,我在完整版本中实现了这些,但一定是在GetHashCode的重写中出错了,您提供的示例非常有用。再次感谢你。
public class Cat
{    
    ...
    public override bool Equals(object other)
    {
        if (this == other) return true;

        Cat cat = other as Cat;
        if (cat == null) return false; // null or not a cat

        if (Name != cat.Name) return false;
        if (!Birthday.Equals(cat.Birthday)) return false;

        return true;
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int result;
            result = Name.GetHashCode();
            result = 29 * result + Birthday.GetHashCode();
            return result;
        }
    }    
}