18

This is my code:

string queryString = "Marco".ToLower();
utenti = db.User.Where(p => 
        queryString.Contains(p.Nickname.ToLower()) ||
            queryString.Contains(p.Nome.ToLower()) ||
            queryString.Contains(p.Cognome.ToLower())).ToList();

but I get:

Only arguments that can be evaluated on the client are supported for the String.Contains method.

Why? Can't I use .Contains()?

4

2 回答 2

38

试试.IndexOf。不是 LINQ 做不到Contains,而是 LINQ to Entities 和 LINQ to SQL 做不到。

string queryString = "Marco";
utenti = db.User.Where(p => 
    queryString.IndexOf(p.Nickname, StringComparison.OrdinalIgnoreCase) >= 0 ||
        queryString.IndexOf(p.Nome, StringComparison.OrdinalIgnoreCase) >= 0 ||
        queryString.IndexOf(p.Cognom, StringComparison.OrdinalIgnoreCasee) >= 0)
.ToList();

为什么?

LINQ 使用延迟执行。这意味着它会等到您想要遍历查询结果时才会执行任何操作。LINQ 有 3 种主要类型:

  1. LINQ to Objects - 当你IEnumerable已经在堆上时。
  2. LINQ to Entities - 当您想使用实体框架查询数据库时。
  3. LINQ to SQL - 当您想使用 LINQ to SQL 查询数据库时。

在第二个 2 的上下文中延迟执行意味着您的查询不会在数据库上执行,直到您在一个foreach块中枚举结果,或调用诸如.ToList,.ToArray等的枚举方法。在此之前,您的查询只是作为表达式树存储在记忆。

db.User如果是内存中的集合,您的查询将非常有效。但是,当数据在数据库中时,LINQ to Entities(或 LINQ to SQL)必须将您的表达式树转换为它所谓的“存储表达式”——这只是“将我的 LINQ 表达式转换为 SQL”的花哨的说法。

现在想象一下,您有一个想要用于查询的自定义 C# 算法,并且您执行了如下操作:

var result = db.User.Where(x => MyCustomMethod(x));

今天,LINQ to Entities 无法将您的 C# 代码转换为 SQL 查询(存储表达式)。您每天依赖的许多其他 C# 方法也是如此。它也不支持.ToLower, .ToUpper, .StartsWith,.EndsWith等。可以转换为存储表达式的 C# 方法数量有限,而.IndexOf恰好是其中之一。

但是请记住,Contains存储表达式不支持我们在这里讨论的字符串对象的方法。LINQ to Entities 确实支持.Containss IEnumerable。以下是有效的,并且可以与 LINQ to Entities 一起使用(不确定 LINQ to SQL):

var idsIWantToFind = new[] { 1, 2, 3 };
var users = db.Where(x => idsIWantToFind.Contains(x.UserId));

以上相当于做一个SQLWHERE UserId IN (1, 2, 3)谓词。

于 2013-11-05T14:32:15.297 回答
-3

问题是输入的优先级。例如:

a.包含(b);或 b. 包含(a);

你最好写:

p.Nickname.Contains(queryString) ...

代替

queryString.Contains(p.Nickname) ...
于 2015-08-22T20:41:18.180 回答