我得出的结论是,对于具有标识列的NHibernate实体,无法正确实现GetHashCode()
。我找到的唯一可行的解决方案是返回常量。请参阅下面的说明。
解释
假设我们有一个Order实体引用一个或多个这样的Product实体:
class Product
{
public virtual int Id { get; set; } // auto; assigned by the database upon insertion
public virtual string Name { get; set; }
public virtual Order Order { get; set; } // foreign key into the Orders table
}
“Id”是SQL Server术语中所谓的IDENTITY列:插入记录时由数据库自动生成的整数键。
现在,我有哪些选项来实施Product.GetHashCode()
?我可以基于
Id
值Name
值这些想法中的每一个都不起作用。如果我将我的哈希代码基于Id,它将在对象插入数据库时更改。以下实验证明,至少在NHibernate.SetForNet4:
存在的情况下会破坏/* add product to order */
var product = new Product { Name = "Sushi" }; // Id is zero
order.Products.Add(product); // GetHashCode() is calculated based on Id of zero
session.SaveOrUpdate(order);
// product.Id is now changed to an automatically generated value from DB
// product.GetHashCode() value changes accordingly
// order.Products collection does not like it; it assumes GetHashCode() does not change
bool isAdded = order.Products.Contains(product);
// isAdded is false;
// the collection is looking up the product by its new hash code and not finding it
基于GetHashCode()
对象标识(即将Product
保留为默认实现)也不能正常工作,之前已在StackOverflow中进行了介绍。如果GetHashCode()
可变,那么Name
基于Name
显然不是一个好主意。
那么,还剩下什么?唯一对我有用的是
class Product
{
...
override public GetHashCode() { return 42; }
}
感谢您阅读这篇长篇大论。 您对如何改善它有什么想法吗?
PS。请记住,这是一个NHibernate问题,而不是收集问题。集合类型和操作顺序不是任意的。它们与NHibernate的工作方式紧密相关。例如,我不能简单地使Order.Products像IList那样。它将具有重要意义,例如需要索引/订单列等。
答案 0 :(得分:2)
我会在Id上建立哈希码(显然是相等的),这是正确的做法。您的问题源于您在对象位于Dictionary中时修改Id的事实。对象在哈希码和相等性方面应该是不可变的,而它们在字典或哈希集中。
您有两种选择 -
<强>更新强>
使用其他映射也可以解决问题
性能存在差异,具体取决于您的映射和方案(请参阅http://nhibernate.info/doc/nh/en/#performance-collections-mostefficientupdate)