我有一个实体,我想与一个子集进行比较,并决定选择除子集之外的所有实体。
所以,我的查询看起来像这样:
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.IEnumerable1[UnitedOne.Data.Sql.Product], System.Collections.Generic.IEqualityComparer
1 [UnitedOne.Data.Sql.Product])” 方法,这个方法不能 翻译成商店表达。
答案 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命令,因此错误