就像在Lambda表达式和LINQ中一样

47
如何使用表达式树来实现类似这样的功能?
customers.Where(c => c.Name **like** "john");

我知道这是不可能的,但我想知道如何实现类似的功能。
注意:我希望使用与SQL相关的LINQ查询解决方案(如Linq to SQL或Linq to entities)。

实际上,您可以生成类似的语句。请查看此处和此处以获取良好示例。 - madcapnmckay
2
如果您使用LINQ to SQL,请选择@Johannes的答案;否则选择@Tom的答案。 - abatishchev
实际上,我没有使用LINQ to SQL或任何LINQ,而是使用表达式树,并构建自己的API,所以我想知道在Lambda表达式中如何完成它,无论如何,我将尝试翻译“containt”表达式并查看是否有效。谢谢大家。 - Stacker
7个回答

85
customers.Where(c => c.Name.Contains("john"));

+1。能够与LINQ over enumerables(LINQ to Object)和LINQ over expression trees(LINQ to SQL、LINQ to Entities等)一起使用。 - Steven
3
它不区分大小写吗? - Charitha Goonewardena

31

如果你的目标是 LINQ to SQL,使用 SqlMethods.Like

customers.Where(c => SqlMethods.Like(c.Name, "%john%")); 

解释:

编译器将从上述语句生成一个表达式树。由于“LIKE”是SQL特定的结构,而不是所有LINQ查询提供程序都共有的,因此使用SqlMethods类及其成员作为表达式编译器(将表达式树编译为SQL)发出“LIKE”语句的“提示”。


3
这当然只适用于LINQ to SQL,不适用于LINQ to Entities或者被称为LINQ to Objects的“LINQ to Enumerable”。 - Steven
是的,我假设他正在使用LinqToSql。我觉得使用string.contains太明显了吧?! - Johannes Rudolph

10

首先想到的是Regex.IsMatch

这可以最接近提供LIKE的功能;例如,您可以这样做:

var matches = people.Where(p => Regex.IsMatch(p.Name, "A.*[mn]"));

foreach (Person match in matches)
{
    Console.WriteLine(match.Name);
}

并获得以下输出:

Adam
Aaron
Aidan

如果您的意图仅是在Name中查找特定子字符串,则像其他人建议的那样使用string.Contains 几乎肯定是首选。


3
现在你有“两个”问题 :)。 - Phil Gan
@Phil:实际上,我不确定是否应该发布这个答案。无论如何,我还是把它作为一个选项留下来了。也许会有人指出这是一个可怕的建议;我不知道。 - Dan Tao
3
@Michael,这并不是一个可怕的建议,我只是在引用一句著名的话:有些人面对问题时会想:“我知道了,我会使用正则表达式。”现在他们有两个问题。 - Phil Gan
哦,我明白了。知道正则表达式后,我甚至理解为什么这句话很出名 :-) - Michael
@PhilGan 我喜欢这个笑话。它很有趣,因为它是真实的,而且很复杂,因为它只适用于行走在这个星球上相当小一部分人群。 - Konrad Viltersten

5
using System.Data.Linq.SqlClient;
...
customers.where(c=>SqlMethods.Like(c.Name, "john"));

3

在where语句中使用Regex.IsMatch,或者使用更简单的版本(不包含通配符等):

customers.where(c=>c.Name.Contains("john"));

1

Here is my code :

string s="somethings";

customers.Where(c => c.Name != null && c.Name.ToLower().Contains(s.ToLower()));

类似这样的东西。


-1
你可以试试这个:
customers.where(c=>EF.Functions.Like(c.Name,"%john%");

我进行了一个测试,看到了生成的SQL语句,以下是结果。
sql = _context.ProdutoPortfolio.Take(10).Where(c => c.NomeProduto.Contains(c.NomeProduto))

sql2 = _context.ProdutoPortfolio.Take(10).Where(c => EF.Functions.Like(c.NomeProduto, $"%{search}%")

结果sql1:如果你使用contains,这就是结果。
DECLARE @__p_0 int = 10;
DECLARE @__search_1 varchar(350) = 'a';

 

SELECT [t].[ProductID], [t].[Cod], [t].[ProductName], [t].[SubThemeName], [t].[ThemeName]
FROM (
     SELECT TOP(@__p_0) [p].[ProductID], [p].[Cod], [p].[ProductName], [p].[SubThemeName], [p].[ThemeName]
     FROM [ProductPortfolio] AS [p]
) AS [t]
WHERE (@__search_1 LIKE '') OR (CHARINDEX(@__search_1, [t].[productName]) > 0)

结果 sql2:

DECLARE @__p_0 int = 10;
DECLARE @__Format_2 varchar(350) = '%a%';

 

SELECT [t].[ProductID], [t].[Cod], [t].[ProductName], [t].[SubThemeName], [t].[ThemeName]
FROM (
     SELECT TOP(@__p_0) [p].[ProductID], [p].[Cod], [p].[ProductName], [p].[SubThemeName], [p].[ThemeName]
     FROM [ProductPortfolio] AS [p]
) AS [t]
WHERE [t].[productname] LIKE @__Format_2

SQL2满足了我的需求,SQL2胜出。

虽然你的答案在我看来是正确的,但如果你能添加一些背景信息来解释(例如)EF.Functions.Like是什么,它来自哪里,它与其他答案有何不同(或相同)...那会更有帮助。 - undefined
@nalka 我更新了我的测试,你可以再次阅读 - undefined
1
他们明确表示不需要任何LINQ-to-anything的解决方案,因此不需要EF。请查看评论。这意味着使用Contains的答案就是他们所需要的。 - undefined
不一定。正如您在上面的测试中所看到的,contains不区分大小写,并且不会捕捉到句子开头的单词,因为它不使用“like”。 - undefined
1
Contains 是区分大小写的,并且在 LINQ-to-objects 中会“捕捉”字符串开头的单词,这也是问题所涉及的内容。 - undefined
你可以尝试,但是 (CHARINDEX(@__search_1, [t].[productName]) > 0) 与 LIKE 是不同的。 - undefined

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