我见过DDD Domain实现,其中实体在构建Equals / GetHashCode方法时依赖主键ID。 我理解为什么这是一个好主意,因为主键可能是唯一不可变的成员。但是,也有可能出现这样的情况。
考虑一个字典,保存刚才实例化的实体。主键(假设它是自动递增值,而不是“业务相关”值)尚未分配,每个实体可能为0。 现在,将保存Dictionary中的实体。这意味着主键的更改会导致不同的哈希码。
我的问题:如果没有与业务相关的主键可用且所有成员都是可变的,那么应该使用哪种模式来使用GetHashCode? p>
提前谢谢。
答案 0 :(得分:6)
在这种情况下,如果已分配了ID,我只会依赖Equals
和GetHashcode
方法中的ID。
在其他情况下,我使用引用比较相等性。
GetHashCode
实施也是如此;如果已分配Id,我只根据'Id'创建一个哈希码。 (也就是说,如果实体不是短暂的)。
下面的代码是我使用的。这有点基于Sharp架构中的实体:
public override bool Equals( object obj )
{
Entity<TId> other = obj as Entity<TId>;
if( other == null || this.GetType() != other.GetType() )
{
return false;
}
bool otherIsTransient = Equals (other.Id, default(TId));
bool thisIsTransient = Equals (this.Id, default (TId));
if( otherIsTransient && thisIsTransient )
{
return ReferenceEquals (this, other);
}
return Id.Equals (other.Id);
}
首先,我检查两个实体是否属于同一类型。 (实际上,您也可以通过实现正确的接口(IEquality<T>
)来创建此方法的类型化版本
当两个实体属于同一类型时,我会检查其中一个是否是瞬态的。我只是通过检查它们的Id属性来做到这一点:如果它包含默认值,则意味着它们尚未保存在数据库中。
如果它们都是瞬态的,我会在它们的参考上比较两个实体。否则,我可以比较他们的身份证。
我使用的GetHashCode方法确保返回的值永远不会改变:
private int? _oldHashCode;
public override int GetHashCode()
{
// Once we have a hash code we'll never change it
if( _oldHashCode.HasValue )
{
return _oldHashCode.Value;
}
bool thisIsTransient = Equals (Id, default(TId));
// When this instance is transient, we use the base GetHashCode()
// and remember it, so an instance can NEVER change its hash code.
if( thisIsTransient )
{
_oldHashCode = base.GetHashCode ();
return _oldHashCode.Value;
}
return Id.GetHashCode ();
}
答案 1 :(得分:1)
您可以检查,假设它是一个自动递增的标识,并且仅在Id上进行比较,如果它们不是0或default(int)
。类似的东西:
public virtual bool Equals(MyClass other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
if (Id != default(int) && other.Id != default(int))
return Equals(Id, other.Id);
return Equals(other.ChildProp, ChildProp);
}
答案 2 :(得分:1)
好吧,如果你不能说一个物体等于另一个物体你就不应该这样做:)
如果equals始终返回false(给定另一个对象而不是自身),则可以。如果不同的本地对象(没有id)在插入db / storage时获得不同的id,这是完全正确的。
如果您可以判断两个对象是相同的并且它们都将映射到同一个表行,因此将在商店中获得相同的ID Equals应该直观地返回true。但你是对的,使用可变值来确定相等(以及特别是哈希码)可能是危险的。收集通常会在您执行此操作时感到困惑。 在这种情况下,最好使用除Equals和GetHashCode之外的其他方法来实现这种相等性,因为它实际上会随着时间的推移而变化。
所以基本上你需要确定你真正需要哪种平等目的。
答案 3 :(得分:1)
我希望您看到的系统使用NHibernate进行ORM。 NHibernate的指南(据称允许您将实体作为POCO,并且对它们不强制执行)推荐这种做法。问题是NH有时难以将实体识别为与另一个实例相同,特别是如果会话已经关闭并重新打开,或者两个代理表示同一个对象。如果不这样做,您可以在集合中两次使用同一实体。请点击此链接获取更多信息: