65

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

LINQ to Entities 无法识别方法 'System.Linq.IQueryable 1[DAL.MyDOClass] Distinct[MyDOClass](System.Linq.IQueryable1[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

4 回答 4

149

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

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

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

var objects = yourResults.GroupBy(o => o.Id).Select(g => g.First());
于 2011-12-19T11:52:45.923 回答
21

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

IEqualityComparer<T>他们的两个答案都涉及' 方法不会被转换为 SQL的事实。

我认为值得看看每个人的优缺点,这不仅仅是评论。

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

Ladislav's 将其从数据库中提取出来,然后再使用内存中的方法。

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

通常,在内存中的情况下,分组比区分更昂贵(特别是如果你用AsList()而不是将它带入内存AsEnumerable())。因此,如果由于某些其他要求,您已经在此阶段将其带入内存,那么它的性能会更高。

如果您的等式定义与仅在数据库中可用的内容没有很好的关系,它也是唯一的选择,当然,如果您想基于IEqualityComparer<T>传递的作为范围。

总而言之,rich's 是我想说的最有可能成为最佳选择的答案,但与 Rich's 相比,Ladislav's 的不同优缺点使其也非常值得研究和考虑。

于 2011-12-19T12:18:59.837 回答
9

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

var query = (from x in context.EntitySet where ...).ToList()
                                                   .Distinct(yourComparer);
于 2011-12-19T11:54:11.553 回答
6

迟到的答案,但你可以做得更好:如果 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 没有任何过载

于 2015-11-15T09:44:53.773 回答