我在一个抽象基类中重写了Equals和GetHashCode,以基于对象的键属性实现值相等。我的主要目的是能够在集合上使用Contains方法而不是Find或FirstOrDefault来检查实例是否已经添加到集合中。
public abstract class Entity
{
public abstract Guid Id { get; }
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (obj.GetType() != GetType())
{
return false;
}
var entity = (Entity)obj;
return (entity.Id == Id);
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
这种方法的问题是我的所有对象在它们被持久化并获得Id(由NHibernate生成)之前是相同的。我做错了吗?我可以在构造函数中生成Id,但我想为使用int id的其他项目实现相同的模式,因此显然不起作用。
在我看来,任何覆盖Equals的对象将在实例化对象后立即等于同一对象的任何其他实例。
编辑添加: 这是我关注的场景:在我的集合的Add方法中,我正在检查以确保集合中还没有包含要添加的对象。如果所有新的对象都相同,那么我永远不能在集合中添加两个新对象。
答案 0 :(得分:2)
NHibernate保证与相同上下文关联的实体的对象引用标识与数据库标识相同。因此,不需要重写Equals()和GetHashCode(),因为这与您要实现的身份相同。
请参阅NHibernate Reference Documentation的10.3. Considering object identity
。
此外,将使用数据库生成的密钥与上下文关联的新实体应该将实体持久地保存到数据库,并将实体的密钥设置为生成的密钥。
答案 1 :(得分:1)
您应该在构造函数中获取您的ID或至少某种标识符。
如果未设置ID(或者是默认值);显然,对于任何相同类型的对象(也没有设置ID),Equals方法将返回true。
答案 2 :(得分:0)
如果Id未初始化,如果你返回“不相等”,它会有帮助吗?
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (obj.GetType() != GetType())
{
return false;
}
var entity = (Entity)obj;
if ((Id == Guid.Empty) || (entity.Id == Guid.Empty))
{
return false;
}
return (entity.Id == Id);
}
答案 3 :(得分:0)
有一个主要细节会影响您的决定:
......我想实现同样的目标 使用的其他项目的模式 int ids ......
通常,会在数据库中生成ID以强制执行唯一性。现在您已经拥有GUID,您不必依赖数据库来生成值 - 保证GUID是唯一的。不要出于错误的原因遵循模式:)
所以继续在构造函数中创建GUID值 - 只需确保有一个setter,以便NHibernate在从数据库中获取实体时可以覆盖该值。
此外,如果您的DBA涉及GUID和数据库碎片,您可能需要考虑使用COMB GUIDs。