使用带有LINQ to Entities Except子句的IEqualityComparer

时间:2010-01-20 16:17:48

标签: linq linq-to-entities iequalitycomparer

我有一个实体,我想与一个子集进行比较,并决定选择除子集之外的所有实体。

所以,我的查询看起来像这样:

Products.Except(ProductsToRemove(), new ProductComparer())

ProductsToRemove()方法在执行一些任务后返回List<Product>。所以最简单的形式是上面的。

ProductComparer()类看起来像这样:

public class ProductComparer : IEqualityComparer<Product>
{
    public bool Equals(Product a, Product b)
    {
        if (ReferenceEquals(a, b)) return true;

        if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
            return false;

        return a.Id == b.Id;
    }

    public int GetHashCode(Product product)
    {
        if (ReferenceEquals(product, null)) return 0;
        var hashProductId = product.Id.GetHashCode();
        return hashProductId;
    }
}

但是,我不断收到以下例外情况:

  

LINQ to Entities无法识别   方法   “System.Linq.IQueryable 1[UnitedOne.Data.Sql.Product] Except[Product](System.Linq.IQueryable 1 [UnitedOne.Data.Sql.Product]   System.Collections.Generic.IEnumerable 1[UnitedOne.Data.Sql.Product], System.Collections.Generic.IEqualityComparer 1 [UnitedOne.Data.Sql.Product])”   方法,这个方法不能   翻译成商店表达。

3 个答案:

答案 0 :(得分:7)

Linq to Entities实际上并没有执行您的查询,它是解释您的代码,将其转换为TSQL,然后在服务器上执行它。

在封面下,它使用操作员和常用功能如何操作以及这些操作与TSQL的关系进行编码。问题是L2E的开发人员不知道你是如何实现IEqualityComparer的。因此他们无法弄清楚当你说A类== B类时你的意思是(例如)“Where Person.FirstName == FirstName AND Person.LastName == LastName”。

因此,当L2E解释器遇到它无法识别的方法时,它会抛出此异常。

有两种方法可以解决这个问题。首先,开发一个满足您的相等要求但不依赖于任何自定义方法的Where()。换句话说,测试实例的属性是否相等,而不是在类上定义的Equals方法。

其次,您可以触发查询的执行,然后在内存中进行比较。例如:

var notThisItem = new Item{Id = "HurrDurr"};
var items = Db.Items.ToArray(); // Sql query executed here
var except = items.Except(notThisItem); // performed in memory

显然,这会带来更多的数据,并且会占用大量内存。第一种选择通常是最好的。

答案 1 :(得分:4)

您尝试将Except调用与自定义IEqualityComparer转换为实体SQL。

显然,您的类无法转换为SQL。

您需要编写Products.AsEnumerable().Except(ProductsToRemove(), new ProductComparer())来强制它在客户端上执行。请注意,这将从服务器下载所有产品。


顺便说一下,你的ProductComparer类应该是单身,如下所示:

public class ProductComparer : IEqualityComparer<Product> {
    private ProductComparer() { }
    public static ProductComparer Instance = new ProductComparer();

    ...
}

答案 2 :(得分:2)

IEqualityComparer<T>只能在本地执行,不能转换为SQL命令,因此错误