如何实现IEqualityComparer返回不同的值?

时间:2011-12-19 11:49:44

标签: c# entity-framework distinct iequalitycomparer

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

  

LINQ to Entities无法识别该方法   “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

4 个答案:

答案 0 :(得分:16)

rich.okelly和Ladislav Mrnka在不同方面都是正确的。

他们的答案都涉及IEqualityComparer<T>的方法不会被翻译成SQL的事实。

我认为值得研究各自的优点和缺点,这不仅仅是评论。

rich的方法将查询重写为具有相同最终结果的其他查询。他们的代码应该或多或少地导致您使用手工编写的SQL有效地执行此操作。

Ladislav在不同之前将其从数据库中拉出来,然后内存中的方法将起作用。

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

一般情况下,在内存情况下分组比分辨率更高(特别是如果使用AsList()而不是AsEnumerable()将其带入内存中)。因此,如果由于某些其他要求而你在此阶段已经将它带入内存,那么它将更具性能。

如果您的等式定义与数据库中的可用内容不相关,那么它也是唯一的选择,当然,如果您希望基于IEqualityComparer<T>作为参数传递。

总之,富人的答案我认为最有可能是这里的最佳选择,但与富人相比,拉迪斯拉夫的不同利弊使得它也值得学习和考虑。

答案 1 :(得分:7)

你不会。在数据库上调用Distinct运算符,因此您在应用程序中编写的任何代码都不能使用(您不能将等式比较器逻辑移动到SQL),除非您对加载所有非不同值并在您的应用

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

答案 2 :(得分:2)

GroupBy()可能比Distinct()更好的解决方案 - 就像在in the top rated answer上提到的this question一样。

答案 3 :(得分:2)

迟到的答案,但你可以做得更好: 如果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;
        }
    }

并且独特的将在没有任何过载的情况下工作。

如果没有,您可以像这样创建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而不会出现任何重载