Entity Framework使用自己的智能方法来检测对象的相等性。例如,如果您调用SaveChanges,则会使用获取对象的值与更新对象的值进行匹配,以检测是否需要SQL更新。
我不确定您对相等性的定义是否会影响此相等性检查,导致某些未更改的项在数据库中被更新,甚至更糟的是,有些更改后的数据没有被更新到数据库中。
注意,您的实体类(即放置在DbSet <...>中的类)代表数据库中的表和表之间的关系。
从数据库提取的两个项目应何时视为代表同一对象?是当它们具有相同的值时吗?在一个数据库中,我们不能有两个名为“John Doe”,出生于7月4日的人吗?
你唯一能够用来检测从数据库提取的两个Persons是否代表同一个Person的方法是通过检查Id。一些非主键值不同只能告诉您已更改的数据未更新到数据库,并不能说明这是不同的Person。
我的建议是尽可能让您的表格表示简单:只包含表的列(非虚拟属性)和表之间的关系(虚拟属性)。没有成员,没有方法,什么都没有。
如果您需要额外的功能,请创建该类的扩展函数。如果您需要非标准的相等比较方法,请创建单独的相等比较器。该类的用户可以决定是否要使用默认比较方法或您的特殊比较方法。
这与各种String Comparers非常类似:StringComparer.OrdinalIgnorCase,StringComparer.InvariantCulture等。
回到您的问题,我觉得您想要一个Gpu比较器,它不检查Id的值:具有不同Id但其他属性值相同的两个项目被认为是相等的。
class GpuComparer : EqualityComparer<Gpu>
{
public static IEqualityComparer<Gpu> IgnoreIdComparer {get;} = new GpuComparer()
public override bool Equals(Gpu x, Gpu y)
{
if (x == null) return y == null;
if (y == null) return false;
if (Object.ReferenceEquals(x, y)) return true;
if (x.GetType() != y.GetType()) return false;
return x.Cores == y.Cores;
}
public override int GetHasCode(Gpu x)
{
if (x == null) throw new ArgumentNullException(nameof(x));
return (x.Cores.HasValue) ? return x.Cores.Value.GetHashCode() : -78546;
}
}
请注意,我添加了对于相同类型的测试,因为如果y是Gpu的派生类,并且您忽略它们不是相同的类型,那么可能会出现Equals(x, y),但不是Equals(y, x),这是相等函数的前提之一。
用法:
IEqualityComparer<Gpu> gpuIgnoreIdComparer = GpuComparer.IgnoreIdComparer;
Gpu x = new Gpu {Id = 0, Cores = null}
Gpu y = new Gpu {Id = 1, Cores = null}
bool sameExceptForId = gpuIgnoreIdComparer.Equals(x, y);
x和y将被视为相等
HashSet<Gpu> hashSetIgnoringIds = new HashSet<Gpu>(GpuComparer.IgnoreIdComparer)
hashSetIgnoringIds.Add(x)
bool containsY = hashSetIgnoringIds.Contains(y)
一种用于计算机的比较器将类似。除了您忘记检查 null 和类型之外,我在您想要进行等式检查的方式中看到了一些其他问题:
- 您的 Gpus 集合可能为空。您必须解决这个问题,以便它不会引发异常。具有 null Gpus 的计算机是否等于具有零 Gpus 的计算机?
- 显然,Gpus 的顺序对您来说并不重要: [1,3] 等于 [3,1]
- 显然,某个 GPU 出现的次数并不重要:[1,1,3] 等于 [1,3,3]?
.
class IgnoreIdComputerComparer : EqualityComparer<Computer>
{
public static IEqualityComparer NoIdComparer {get} = new IgnoreIdComputerCompare();
public override bool (Computer x, Computer y)
{
if (x == null) return y == null;not null
if (y == null) return false;
if (Object.ReferenceEquals(x, y)) return true;
if (x.GetType() != y.GetType()) return false;
if (x.Gpus == null || x.Gpus.Count == 0)
return y.Gpus == null || y.Gpus.Count == 0;
HashSet<Gpu> xGpus = new HashSet<Gpu>(x, GpuComparer.IgnoreIdComparer);
return xGpush.EqualSet(y);
}
public override int GetHashCode(Computer x)
{
if (x == null) throw new ArgumentNullException(nameof(x));
if (x.Gpus == null || x.Gpus.Count == 0) return -784120;
HashSet<Gpu> xGpus = new HashSet<Gpu>(x, GpuComparer.IgnoreIdComparer);
return xGpus.Sum(gpu => gpu);
}
}
如果你要使用大量的GPU,请考虑使用更智能的GetHashCode。