我有一个简单的应用程序,用户可以打开订单,对它们进行更改,然后将它们保存回数据库。当订单打开时,我会像这样从数据库中检索它
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被设置为null。谁能告诉我为什么?
我在这里使用nHibernate的方式有什么问题吗?重申我的所作所为:
这是否可以使用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);
这是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();
}
}
答案 0 :(得分:1)
您能否显示用于将项目添加到评论集合的代码?
您需要让NHibernate管理注释集合,因此请确保您没有将Comments属性重新设置为new List<OrderComment>
或类似的东西,请确保您保留相同的NHibernate实例化代理并添加/删除/必要时清除其值。
答案 1 :(得分:1)
我认为HashCode
不应该来自Id
。 Order.Comments
是一个基于哈希的集合。评论的开头都有Id 0
。添加到集合时,HashCode
为0
。