Entity framework 4 为POCO实现IEquatable

Entity framework 4 为POCO实现IEquatable,entity-framework-4,iequatable,Entity Framework 4,Iequatable,我注意到EF的DbSet.Add()非常慢。在谷歌上搜索一下,发现了一个承诺性能提高180倍的答案: 然而,我并不完全理解如何按照答案中的建议实施IEquatable ,如果我实现了IEquatable,我还应该重写Equals()和GetHashCode() 与许多POCO一样,我的对象是可变的。在提交到数据库(SaveChanges())之前,新对象的Id为0。保存对象后,Id是实现IEquatable、Equals()和GetHashCode()的理想基础 在哈希代码中包含任何可变属性是

我注意到EF的DbSet.Add()非常慢。在谷歌上搜索一下,发现了一个承诺性能提高180倍的答案:

然而,我并不完全理解如何按照答案中的建议实施
IEquatable

,如果我实现了
IEquatable
,我还应该重写
Equals()
GetHashCode()

与许多POCO一样,我的对象是可变的。在提交到数据库(
SaveChanges()
)之前,新对象的Id为0。保存对象后,Id是实现IEquatable、Equals()和GetHashCode()的理想基础

在哈希代码中包含任何可变属性是不明智的,因为

如果两个对象比较相等,则每个对象的GetHashCode方法 对象必须返回相同的值

我是否应该将
IEquatable
实现为逐个属性比较的属性(例如
this.FirstName==other.FirstName
),而不重写Equals()和GetHashCode()

鉴于我的POCO是在EntityFramework上下文中使用的,是否应该特别注意Id字段

与许多POCO一样,我的对象是可变的

但是,在作为主键的字段上,tehy不应该是可变的。根据定义,或者你是在一个世界的痛苦数据库无论如何以后

仅在主键的字段上生成哈希代码

如果参与的对象具有相同的哈希代码,则Equals()必须返回true

BZZZ-错误

哈希代码是双重的。两个对象可能具有不同的值和smae哈希代码。hsahsode是一个整数(32位)。字符串的长度可以是2gb。不能将每个可能的字符串映射到单独的哈希代码

如果两个对象具有相同的哈希代码,则它们可能不同。如果两个对象相同,则它们不能有不同的哈希代码

对于具有相同哈希代码的对象,Equals必须返回true,这是从哪里得到的


此外,无论是否为PCO,映射到数据库并在关系中使用的对象必须具有稳定的主键(可用于运行哈希代码计算)。没有此STIL的对象应该具有主键(根据SQL Server要求),使用序列/人工主键在此处有效。再次使用它来运行HashCode计算。

第一件事:对不起,我的蹩脚英语:)

正如TomTom所说,它们不应该因为还没有收到PK/Id而变

在我们的EF:CF系统中,我们为每个新POCO使用生成的负id(在基类ctor中分配,或者,如果使用ProxyTracking,在ObjectMaterialized event中分配)。这个想法很简单:

公共静态类IdKeeper
{
专用静态int m_Current=int.MinValue;
私有静态Next()
{
返回++m_电流;
}
}
MinValue和incremen应该很重要,因为在将更改提交到db之前,EF将按照它们的PK对POCO进行排序,并且当您使用“-1,-2,-3”时,POCO被翻转保存,这在某些情况下(不根据排序)可能不理想

公共抽象类IdBase
{
公共虚拟整数Id{get;set;}
受保护的IdBase()
{
Id=IdKeeper.Next();
}
}
如果POCO是从DB具体化的,那么当您调用SaveChanges()时,他的Id将被实际PK覆盖。作为奖励,每一个“尚未保存”的POCO id都是唯一的(总有一天会派上用场的;)

将两个POCO与IEquatable()进行比较很容易:

公共类人物
:IdBase,i足够
{
公共虚拟字符串FirstName{get;set;}
公共布尔等于(其他人)
{
返回Id==other.Id;
}
}

我在寻找同一问题的解决方案时遇到了你的问题。下面是我正在尝试的一个解决方案,看看它是否满足您的需求:

首先,我所有的POCO都来自这个抽象类:

公共抽象类BasePOCO:IEquatable其中T:class
{
私有只读Guid_Guid=Guid.NewGuid();
#区域可容纳成员
公共抽象布尔等于(T其他);
#端区
公共覆盖布尔等于(对象对象对象)
{
if(ReferenceEquals(null,obj))
{
返回false;
}
if(ReferenceEquals(this,obj))
{
返回true;
}
if(obj.GetType()!=typeof(T))
{
返回false;
}
收益等于((T)obj);
}
公共覆盖int GetHashCode()
{
返回_guid.GetHashCode();
}
}
我创建了一个只读Guid字段,用于GetHashCode()覆盖。这将确保如果我将派生的POCO放入字典或其他使用散列的东西中,如果我在此期间调用了.SaveChanges(),并且ID字段由基类更新,我不会将其孤立。这是一个我不确定是否完全正确的部分,或者它是否比base.GetHashCode()更好?。我抽象了Equals(T other)方法,以确保实现类必须以某种有意义的方式实现它,最有可能的方式是使用ID字段。我将Equals(objectobj)覆盖放在这个基类中,因为它可能对所有派生类也是相同的

这将是抽象类的一个实现:

公共类物种:BasePOCO
{
公共int ID{get;set;}
公共字符串LegacyCode{get;set;}
公共字符串名称{get;set;}
公共覆盖布尔等于(其他物种)
{
if(ReferenceEquals(null,其他))
{
返回false;
}
if(ReferenceEquals(this,other))
{
返回true;
}
返回ID!=0&&
ID==other.ID&&
LegacyCode==其他.LegacyCode&&
Name==其他.Name;
}
}
ID属性被设置为数据库中的主键,EF知道这一点。对于新创建的对象,ID为0,然后获取