gpt4 book ai didi

entity-framework-4 - 为 POCO 实现 IEquatable

转载 作者:行者123 更新时间:2023-12-04 15:25:42 24 4
gpt4 key购买 nike

我注意到 EF 的 DbSet.Add() 很慢。稍微谷歌搜索一下就找到了一个 SO 答案,它 promise 将性能提高 180 倍:

https://stackoverflow.com/a/7052504/141172

但是,我不明白如何实现 IEquatable<T>正如答案中所建议的那样。

According to MSDN ,如果我实现 IEquatable<T> ,我也应该覆盖 Equals()GetHashCode() .

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

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

If two objects compare as equal, the GetHashCode method for each object must return the same value



我应该实现 IEquatable<T>作为逐个属性的比较(例如 this.FirstName == other.FirstName )而不覆盖 Equals() 和 GetHashCode()?

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

最佳答案

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

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

public abstract class BasePOCO <T> : IEquatable<T> where T : class
{
private readonly Guid _guid = Guid.NewGuid();

#region IEquatable<T> Members

public abstract bool Equals(T other);

#endregion

public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != typeof (T))
{
return false;
}
return Equals((T)obj);
}

public override int GetHashCode()
{
return _guid.GetHashCode();
}
}

我创建了一个只读的 Guid 字段,我在 GetHashCode() 覆盖中使用了该字段。这将确保如果我将派生的 POCO 放入字典或其他使用哈希的东西中,如果我在此期间调用了 .SaveChanges() 并且 ID 字段由基类更新,我不会孤立它这是我不确定的一部分是否完全正确,或者它是否比 Base.GetHashCode() 更好?我抽象了 Equals(T other) 方法以确保实现类必须以某种有意义的方式实现它,最有可能使用 ID 字段。我将 Equals(object obj) 覆盖放在这个基类中,因为它对于所有派生类也可能相同。

这将是抽象类的实现:

public class Species : BasePOCO<Species>
{
public int ID { get; set; }
public string LegacyCode { get; set; }
public string Name { get; set; }

public override bool Equals(Species other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return ID != 0 &&
ID == other.ID &&
LegacyCode == other.LegacyCode &&
Name == other.Name;
}
}

ID 属性设置为数据库中的主键,EF 知道这一点。 ID 在新创建的对象上为 0,然后在 .SaveChanges() 上设置为唯一的正整数。所以在重写的 Equals(Species other) 方法中,null 对象显然不相等,相同的引用显然是,那么我们只需要检查 ID == 0。如果是,我们就说两个相同类型的对象两者的 ID 为 0 不相等。否则,如果它们的性质都相同,我们就说它们相等。

我认为这涵盖了所有相关情况,但如果我不正确,请指出。希望这可以帮助。

=== 编辑 1

我在想我的 GetHashCode() 不对,我看了这个 https://stackoverflow.com/a/371348/213169关于题目的回答。上面的实现将违反返回 Equals() == true 的对象必须具有相同哈希码的约束。

这是我的第二次尝试:

public abstract class BasePOCO <T> : IEquatable<T> where T : class
{
#region IEquatable<T> Members

public abstract bool Equals(T other);

#endregion

public abstract override bool Equals(object obj);
public abstract override int GetHashCode();
}

和实现:

public class Species : BasePOCO<Species>
{
public int ID { get; set; }
public string LegacyCode { get; set; }
public string Name { get; set; }

public override bool Equals(Species other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return ID != 0 &&
ID == other.ID &&
LegacyCode == other.LegacyCode &&
Name == other.Name;
}

public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
return Equals(obj as Species);
}

public override int GetHashCode()
{
unchecked
{
return ((LegacyCode != null ? LegacyCode.GetHashCode() : 0) * 397) ^
(Name != null ? Name.GetHashCode() : 0);
}
}

public static bool operator ==(Species left, Species right)
{
return Equals(left, right);
}

public static bool operator !=(Species left, Species right)
{
return !Equals(left, right);
}
}

所以我去掉了基类中的 Guid 并将 GetHashCode 移到了实现中。我将 Resharper 的 GetHashCode 实现与除 ID 之外的所有属性一起使用,因为 ID 可能会改变(不想要孤儿)。这将满足上述链接答案中对相等性的约束。

关于entity-framework-4 - 为 POCO 实现 IEquatable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9782235/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com