C# nHibernate神秘地从多对一关系中删除项目
我有一个简单的应用程序,用户可以打开订单,对其进行更改,然后将其保存回数据库。当打开订单时,我会像这样从数据库中检索它C# nHibernate神秘地从多对一关系中删除项目,c#,.net,nhibernate,C#,.net,Nhibernate,我有一个简单的应用程序,用户可以打开订单,对其进行更改,然后将其保存回数据库。当打开订单时,我会像这样从数据库中检索它 ISession session = SessionFactory.OpenSession(); ... Order order = session.Query<Order>() .Where(o => o.Id == id) .FirstOrDefault(); 最后,
ISession session = SessionFactory.OpenSession();
...
Order order = session.Query<Order>()
.Where(o => o.Id == id)
.FirstOrDefault();
最后,当用户关闭订单时,我将处理会话
这里有一个问题:如果用户添加注释并保存,然后在关闭订单之前添加另一条注释并再次保存,则第一条注释将在第二次保存期间删除。下面是从第二次保存输出的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();
}
}
这是注释类。Id在基类PersistentObject
中实现:
公共类注释:PersistentObject
{
公共用户作者{get;private set;}
已创建公共日期时间{get;private set;}
公共字符串文本{get;private set;}
}
公共抽象类PersistentObject
{
公共虚拟T Id{get;受保护的内部集;}
公共覆盖布尔等于(对象对象对象)
{
//如果两个对象都未保存到数据库,则无法比较Id,因为
//两者都将为0。在这种情况下,请使用引用相等。
PersistentObject other=对象作为PersistentObject;
如果(其他==null)
返回false;
bool thisIsDefault=object.Equals(Id,默认值(T));
bool otherIsDefault=object.Equals(other.Id,默认值(T));
if(thisIsDefault&&otherIsDefault)
return object.ReferenceEquals(this,other);
else if(thisIsDefault | | otherIsDefault)
返回false;
其他的
返回object.Equals(this.Id,other.Id);
}
公共覆盖int GetHashCode()
{
返回Id.GetHashCode();
}
}
能否显示用于将项目添加到评论集合的代码
您需要让NHibernate管理注释集合,因此请确保您没有将注释属性重新设置为
新列表
或类似内容,确保保留相同的NHibernate实例化代理,并根据需要添加/删除/清除其值。我不认为HashCode
应该取自Id
Order.Comments
是一个集合,它基于散列。所有注释的开头都有一个Id0
。当添加到集合中时,将使用HashCode
,当它为0
时,谢谢您的回答。我已经用更多信息更新了我的问题。我绝对不会重新设置_comments字段。我唯一一次设置它是在字段初始化器中,之后nHibernate设置了它,我使用它。消息ID从哪里来?对不起,应该是OrderId。是的,这就是问题所在!如果我删除了对GetHashCode的覆盖,那么nHibernates不会在第二次保存时删除第一条注释。但我不明白这为什么会造成问题。在看到您的答案后,我尝试将收藏从一套改为一个包,这也解决了问题。所以我猜nHibernate决定了这两条评论是相等的,只允许其中一条进入集合,就必须删除另一条。但是我的Equals override对于这2条注释永远不会返回true,那么为什么我错误的GetHashCode实现导致了这个错误呢?对于任何感兴趣的人来说,这是一个如何正确实现GetHashCode()的建议。我不知道,这很奇怪。当我乱搞散列代码时,我还体验到了用词上的奇怪行为。我学到的一件事是,它永远不应该改变它的值,这使得NH或DB创建的id是一个糟糕的候选者。在我们当前的项目中,我们使用的guid不是主键,而是用于此类标识。
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)]
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);
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();
}
}