如何实现IEqualityComparer返回不同的值

本文关键字:返回 IEqualityComparer 何实现 实现 | 更新日期: 2023-09-27 18:18:21

我有一个L2E查询,它返回一些包含重复对象的数据。我需要删除那些重复的对象。基本上,我应该假设如果它们的id相同,那么对象就是重复的。我试过q.Distinct(),但仍然返回重复的对象。然后我尝试实现我自己的IEqualityComparer并将其传递给Distinct()方法。方法失败,文本如下:

对实体的LINQ不识别该方法System.Linq.IQueryable 1[DAL.MyDOClass] Distinct[MyDOClass](System.Linq.IQueryable 1[DAL。MyDOClass),System.Collections.Generic.IEqualityComparer"1 [DAL.MyDOClass])"方法,且该方法不能转换为存储表达式。

下面是EqualityComparer的实现:

  internal class MyDOClassComparer: EqualityComparer<MyDOClass>
    {
        public override bool Equals(MyDOClass x, MyDOClass y)
        {
            return x.Id == y.Id;
        }
        public override int GetHashCode(MyDOClass obj)
        {
            return obj == null ? 0 : obj.Id;
        }
    }

那么我如何正确地编写自己的IEqualityComparer ?

如何实现IEqualityComparer返回不同的值

EqualityComparer不是要走的路-它只能过滤内存中的结果集例如:

var objects = yourResults.ToEnumerable().Distinct(yourEqualityComparer);

您可以使用GroupBy方法按ID分组,使用First方法让数据库只检索每个ID的唯一条目,例如:

var objects = yourResults.GroupBy(o => o.Id).Select(g => g.First());

kelly和Ladislav Mrnka在不同方面都是正确的。

他们的答案都处理了IEqualityComparer<T>的方法不会被转换成SQL的事实。

我认为值得看看每一个的优缺点,这将需要更多的评论。

rich的方法将查询重写为具有相同最终结果的不同查询。他们的代码或多或少会导致你如何有效地使用手工编写的SQL。

Ladislav's将它在distinct之前的点从数据库中取出,然后内存中的方法将工作。

由于数据库非常擅长进行分组和过滤富的依赖,因此在这种情况下,它可能是性能最高的。但是,您可能会发现,在此分组之前发生的事情的复杂性使得Linq-to-entities不能很好地生成单个查询,而是生成一堆查询,然后在内存中完成一些工作,这可能非常讨厌。

一般来说,在内存情况下,分组比区分更昂贵(特别是使用AsList()而不是AsEnumerable()将其放入内存时)。因此,如果由于其他一些需求,您已经打算在这个阶段将它放入内存中,那么它将具有更高的性能。

如果你的相等性定义与数据库中可用的内容不太相关,这也是唯一的选择,当然,如果你想基于作为参数传递的IEqualityComparer<T>来切换相等性定义。

总而言之,rich’s是我认为最有可能是最佳选择的答案,但是与rich’s相比,Ladislav’s的优点和缺点也很值得研究和考虑。

你不会的。Distinct运算符在数据库上被调用,所以你在应用程序中编写的任何代码都不能被使用(你不能将你的相等比较器逻辑移动到SQL),除非你很高兴在你的应用程序中加载所有非不同的值并进行不同的过滤。

var query = (from x in context.EntitySet where ...).ToList()
                                                   .Distinct(yourComparer);

回答晚了,但你可以做得更好:如果DAL对象是部分的(通常是DB对象),您可以这样扩展它:

public partial class MyDOClass :  IEquatable<MyDOClass>
    {
        public override int GetHashCode()
        {
            return Id == 0 ? 0 : Id;
        }
        public bool Equals(MyDOClass other)
        {
            return this.Id == other.Id;
        }
    }

在没有任何重载的情况下,distinct也可以工作。

如果没有,你可以像这样创建IEqualityComparer类:

internal class MyDOClassComparer : MyDOClass,  IEquatable<MyDOClass>, IEqualityComparer<MyDOClass>
    {
        public override int GetHashCode()
        {
            return Id == 0 ? 0 : Id;
        }
        public bool Equals(MyDOClass other)
        {
            return this.Id == other.Id;
        }
        public bool Equals(MyDOClass x, MyDOClass y)
        {
            return x.Id == y.Id;
        }
        public int GetHashCode(MyDOClass obj)
        {
            return Id == 0 ? 0 : Id;
        }
    }

同样,使用不重载的Distinct