1

我有一个简单的应用程序,用户可以在其中打开订单,对其进行更改,然后将它们保存回数据库。打开订单后,我会像这样从数据库中检索它

ISession session = SessionFactory.OpenSession();

...

Order order = session.Query<Order>()
                     .Where(o => o.Id == id)
                     .FirstOrDefault();

为了启用 order.Comments 的延迟加载,我保持会话打开,直到订单关闭。以下是映射:

<class name="Order">
    <id name="Id">
        <generator class="identity" />
    </id>    

...

    <set name="Comments" access="field.camelcase-underscore" cascade="all-delete-orphan"    lazy="true" order-by="Created">
      <key column="OrderId" />
      <one-to-many class="Comment" />
    </set>     
</class>

<class name="Comment" table="OrderComment" lazy="false">
    <id name="Id">
      <generator class="identity" />
    </id>
    <many-to-one name="Author" />
    <property name="Created" />
    <property name="Text" length="1000" />
</class>

该应用程序的设计使得在订单打开时,可以在关闭之前多次保存。我这样保存:

using (ITransaction trans = session.BeginTransaction())
{
    session.SaveOrUpdate(order)
    trans.Commit();
}

最后,当用户关闭订单时,我处理了会话。

这里有问题:如果用户添加评论,保存,然后在关闭订单之前添加另一个评论并再次保存,则在第二次保存期间删除第一个评论。这是第二次保存输出的sql:

NHibernate: INSERT INTO OrderComment (Id, Author, Created, Text) VALUES (hibernate_sequence.nextval, :p0, :p1, :p2) returning Id into :nhIdOutParam;:p0 = 1 [Type: Int32 (0)], :p1 = 14.01.2013 12:53:20 [Type: DateTime (0)], :p2 = '2' [Type: String (0)], :nhIdOutParam = NULL [Type: Int32 (0)]

**NHibernate: UPDATE OrderComment SET OrderId = null WHERE OrderId = :p0 AND Id = :p1;:p0 = 465 [Type: Int32 (0)], :p1 = 591 [Type: Int32 (0)]**

NHibernate: UPDATE OrderComment SET OrderId = :p0 WHERE Id = :p1;:p0 = 465 [Type: Int32 (0)], :p1 = 592 [Type: Int32 (0)]

所以问题是粗体的那一行——第一条评论的 OrderId 被设置为空。谁能告诉我为什么?

我在这里使用 nHibernate 的方式有什么问题吗?重申我的工作:

  1. 打开会话
  2. 检索对象
  3. 用户更新对象
  4. 通过开始事务保存对象,调用 session.SaveOrUpdate(object),然后提交事务。
  5. 重复步骤 3 和 4 任意次数。
  6. 处理会话。

这是一种可接受的使用方式nHibernate吗?

编辑

这是 Order 类中的 comments 属性:

ICollection<Comment> _comments = new List<Comment>();
public virtual ReadOnlyCollection<Comment> Comments
{
    get 
    {
        return _comments.ToList().AsReadOnly(); 
    }
}

然后通过调用以下方法添加注释:

public virtual void AddComment(Comment comment)
{
    _comments.Add(comment);    
}

 ...

Comment comment = new Comment()
{
    Author = User.Current,
    Created = DateTime.Now,
    Text = text
};

order.AddComment(comment);

这是评论类。Id 在基类中实现PersistentObject<T>

public class Comment : PersistentObject<int>
{        
    public User Author { get; private set; }
    public DateTime Created { get; private set; }
    public string Text { get; private set; }                                             
}

public abstract class PersistentObject<T>
{        
    public virtual T Id { get; protected internal set; }       

    public override bool Equals(object obj)
    {
        // If both objects have not been saved to database, then can't compare Id because this
        // will be 0 for both.  In this case use reference equality.

        PersistentObject<T> other = obj as PersistentObject<T>;
        if (other == null)
            return false;

        bool thisIsDefault = object.Equals(Id, default(T));
        bool otherIsDefault = object.Equals(other.Id, default(T));

        if (thisIsDefault && otherIsDefault)
            return object.ReferenceEquals(this, other);
        else if (thisIsDefault || otherIsDefault)
            return false;
        else
            return object.Equals(this.Id, other.Id);
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }        
}
4

2 回答 2

1

我不认为HashCode应该从Id. Order.Comments是一个集合,它基于散列。0评论的开头都有一个ID 。HashCode是在添加到集合时采用的,当它是时0

于 2013-01-14T16:14:00.740 回答
1

您能否展示用于将项目添加到评论集合中的代码?

您需要让 NHibernate 管理评论的集合,因此请确保您没有将 Comments 属性重新设置为 anew List<OrderComment>或类似的东西,确保您保留相同的 NHibernate 实例化代理并根据需要添加/删除/清除其值。

于 2013-01-14T15:05:47.553 回答