将IEqualityComparer与LINQ一起用于实体除外子句

问题描述 投票:5回答:3

我有一个实体想与一个子集进行比较,并确定选择该子集以外的所有实体。

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

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.IQueryable1[UnitedOne.Data.Sql.Product] Except[Product](System.Linq.IQueryable1 [UnitedOne.Data.Sql.Product],System.Collections.Generic.IEnumerable1[UnitedOne.Data.Sql.Product], System.Collections.Generic.IEqualityComparer1 [UnitedOne.Data.Sql.Product])'方法,并且该方法不能是转换为商店表达式。

linq linq-to-entities iequalitycomparer
3个回答
7
投票

Linq to Entities实际上不是在执行查询,它是在代码中[[解释,将其转换为TSQL,然后在服务器上执行。

在幕后,使用操作符和公用函数的操作方式以及它们与TSQL的关系知识进行编码。问题是L2E的开发人员不知道您到底如何实现IEqualityComparer。因此,他们无法弄清楚,当您说Class A == Class 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

显然,这将通过导线带来更多的数据,并且会占用更多的内存。通常,第一个选项是最好的。

4
投票
您正在尝试将具有自定义ExceptIEqualityComparer调用转换为Entity SQL。

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

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


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

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


2
投票
IEqualityComparer<T>只能在本地执行,不能转换为SQL命令,因此会出现错误
© www.soinside.com 2019 - 2024. All rights reserved.