LINQ To SQL 异常:本地序列不能用于 LINQ to SQL 查询操作符的实现,除了 Contains 操作符。

23
考虑以下这个 LINQ To SQL 查询。它的目的是将一个字符串数组的搜索词应用到 SQL 表的许多不同字段上: ```html

Consider this LINQ To SQL query. It's intention is to take a string[] of search terms and apply the terms to a bunch of different fields on the SQL table:

```
string[] searchTerms = new string[] {"hello","world","foo"};
List<Cust> = db.Custs.Where(c => 
   searchTerms.Any(st => st.Equals(c.Email))
|| searchTerms.Any(st => st.Equals(c.FirstName))
|| searchTerms.Any(st => st.Equals(c.LastName))
|| searchTerms.Any(st => st.Equals(c.City))
|| searchTerms.Any(st => st.Equals(c.Postal))
|| searchTerms.Any(st => st.Equals(c.Phone))
|| searchTerms.Any(st => c.AddressLine1.Contains(st))
)
.ToList();

出现了一个异常:

除了 Contains() 操作符之外,本地序列不能用于 LINQ to SQL 查询运算符的实现

问题: 为什么会出现此异常,如何重写查询以避免此异常?

4个回答

33

在查询中将 Any 的用法替换为 Contains。例如:

searchTerms.Contains(c.Email)

这是应该可以得到您想要的结果。看起来有些奇怪,但它是正确的 - 它将为Contains中的每个字段生成一个IN操作符,并包括searchTerms中的所有元素。

AddressLine1部分不会像这样工作 - 您需要自己生成循环比较。

c.addressLine1.Contains(...)

类似PredicateBuilder这样的工具可能对此有帮助。


@nitzmahone:谢谢,我会去看看PredicateBuilder,它看起来很有前途! - p.campbell
我会担心在 LinqToSql 实现中,PredicateBuilder 的强大功能可能会让人失望,因为一些条件可能无法被 LinqToSql 提供程序实现(这正是你在问题中描述的确切问题)。 - Matt Kocaj
+1 for the .Contains() - 通常是 LinqToSql 不支持的等式的良好替代品。建议小心使用 PredicateBuilder - Matt Kocaj
我经常使用PredicateBuilder,几乎只与Linq to SQL一起使用。它可以节省大量时间,并且在列列表是可变的(即“高级搜索”)时,这几乎是唯一的执行OR'd动态搜索的方法。 - nitzmahone

11

只是一个想法(与问题不直接相关,但可能会帮助其他查看者):

我遇到了与您相同的错误消息,即使我正确使用了Contains()方法,但花费了我很长时间才弄清楚我的问题根源是将IEnumerable返回给需要进一步过滤L2S查询结果的东西。一旦我将函数的返回类型更改为IQueryable,问题就消失了。这是有道理的,因为IEnumerable无法进一步过滤,但IQueryable可以。


0

本质上,这个错误是在告诉你正在对两个集合进行连接,其中一个是数据库表,另一个是数组。LINQ 不适用于处理这种情况——要么两者都在数据库中,要么两者都在内存中(使用 Contains 时有特殊情况例外)。


0

我也遇到了同样的错误,但是上面发布的解决方案都没有起作用。

对我有用的方法是先将 db.Custs 强制转换为列表 ,如下所示:

List<Cust> =db.Custs.ToList<Cust>.Where(...

我不知道为什么它能工作,但它确实做到了。


3
这在你的情况下可行,因为你绕过了数据库,而是针对集合进行操作,而不是将Contains()扩展方法翻译成SQL语句。 - p.campbell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接