实体框架 EF.Functions.Like vs string.Contains

Posted

技术标签:

【中文标题】实体框架 EF.Functions.Like vs string.Contains【英文标题】:Entity framework EF.Functions.Like vs string.Contains 【发布时间】:2018-01-24 07:27:34 【问题描述】:

我正在阅读实体框架核心2.0 https://blogs.msdn.microsoft.com/dotnet/2017/08/14/announcing-entity-framework-core-2-0/的公告

它说他们添加了新的 Sql 函数,例如 EF.Functions.Like 来执行 SQL LIKE 操作。

我想知道,EF.Functions.Likestring.Contains/StartsWith 之间有什么区别?

例如:

var customers = context.Customers.Where(c => c.Name.StartsWith("a")); // Version A
var customers = context.Customers.Where(c => EF.Functions.Like(c.Name, "a%")); // Version B

这两个版本有什么区别? EF 已经知道如何将string.Contains/StartsWith 翻译成相应的 SQL 操作了,不是吗?

我能想到的唯一原因是 EF.Functions.Like 将允许更复杂的模式,例如 "a%b%"(尽管这个可以写成 StartsWith("a") && Contains("b")

是这个原因吗?

【问题讨论】:

检查 SQL 语句。最有可能的是,它们是相同的。 .StartsWith 被翻译成LIKE 'a%'。另一方面,包含 将被转换为LIKE '%a%',这是一个非常糟糕的主意。 LIKE 'a%' 可以利用索引,因为它本质上是一个范围搜索。 LIKE '%a%' 虽然必须处理所有行以查找模式是否匹配 是的,就是这个原因 是的,正如我所怀疑的那样,如果他们为它提供一个扩展方法会好很多,c.Name.Like(...) 如果您没有为“like”提供字符大小写,它只会搜索您提供的字符或单词。也包含做同样的事情。但为了避免字符大小写,你可以使用如下: string k = "I like your style"; StringComparison stringComparison = StringComparison.CurrentCultureIgnoreCase; Console.WriteLine(k.IndexOf("your", stringComparison)); 只是灵活性更高。阅读.Like('abc%def%ghi') 会更容易,然后尝试使用不同的树方法编写相同的内容。 【参考方案1】:

like 查询支持wildcard characters,因此在某些场景下与字符串扩展方法相比非常有用。

例如:如果我们要搜索所有以 'ri' 作为中间字符的 4 个字母名称,我们可以这样做 EF.Functions.Like(c.Name, "_ri_");

或获取所有以元音开头的城市的客户:

var customers = from c in context.Customers 
                   where EF.Functions.Like(c.City, "[aeiou]%")
                   select c;

(请阅读@Tseng 的回答,了解它们如何以不同方式转换为 SQL 查询)

【讨论】:

还考虑阅读 #474 Query: Improve translation of String's StartsWith, EndsWith and Contains 线程,而不是出于此决定背后的灵活性原因。【参考方案2】:

@adiga 的答案相当不完整,仅涵盖了部分用法差异。

但是,.StartsWith(...).Contains(...).EndsWith(...) 转换为 SQL 的方式也与 EF.Functions.Like 不同。

例如,.StartsWith 被翻译为(string LIKE pattern + "%" AND CHARINDEX(pattern, string) = 1) OR pattern = '',而.Contains 被翻译为(CHARINDEX(pattern, string) > 0) OR pattern = ''

EF.Functions.Like 但是被翻译成string LIKE pattern [ESCAPE escapeChar]

这也可能对性能产生影响。以上对 EF Core SqlServer 提供程序有效。其他 EF Core 提供程序可能会以不同方式对其进行翻译。

【讨论】:

哪个更快? @ChrisGo 以我个人的经验,等号运算符 (==) 是最快的,其次是 StartsWith 和 EndsWith,它们与等号运算符很接近,并且 contains 是最慢且效率最低的,因为它需要逐个位置比较整个字符串的搜索词长度。当您可以使用等号运算符时,第二好的选择是用于搜索和过滤目的的 StartsWith。 @revobtz:不确定你是否意识到,这不是关于 C# 字符串操作,而是关于 SQL(以及使用这些操作的 Entity Framework Core 表达式如何转换为 SQL) @Tseng:我一直在谈论 SQL 和实体框架......即使这是在谈论字符串,它的行为仍然几乎相同,但当然你不会看到任何使用字符串时的性能差异,因为 sql 需要执行额外的操作来进行搜索过滤。我使用过很多数据库引擎 Sql Server、Oracle、mysql、MariaDB、Postgress、MongoDB,其中一些引擎我知道如何调整它们。 :)

以上是关于实体框架 EF.Functions.Like vs string.Contains的主要内容,如果未能解决你的问题,请参考以下文章

实体框架核心中等效的 SQL RIGHT 函数

Linq WHERE EF.Functions.Like - 为啥直接属性起作用而反射不起作用?

EF Core 5 - 如何将 EF.Functions.Like 与映射到 JSON 字符串的自定义属性一起使用?

[EF]关于EF使用Contains关键字的问题

[EF]关于EF使用Contains关键字的问题

DbContext 代码生成策略在实体框架 5 和 VS 2012 中失败