简体   繁体   English

实体框架核心 - 包含区分大小写还是不区分大小写?

[英]Entity Framework core - Contains is case sensitive or case insensitive?

"Contains" in Entity Framework core should equivalent to the SQL %like% operator.实体框架核心中的“包含”应该等同于 SQL %like% 运算符。 Therefore "Contains" should be case insensitive however it is case sensitive!因此“包含”应该不区分大小写,但它区分大小写! (at least in postgres????) (至少在 postgres 中????)

The following only outputs a result when the correct casing for keyword is used.以下仅在使用正确的关键字大小写时输出结果。

context.Counties.Where(x => x.Name.Contains(keyword)).ToList();

What am I doing wrong?我究竟做错了什么?

It used to be the case for older versions of EF core.旧版本的 EF 核心曾经是这种情况。 Now string.Contains is case sensitive, and for exemple for sqlite it maps to sqlite function `instr()' ( I don't know for postgresql).现在string.Contains区分大小写,例如 sqlite 它映射到 sqlite 函数 `instr()'(我不知道 postgresql)。

If you want to compare strings in a case-insensitive way, you have DbFunctions to do the jobs.如果您想以不区分大小写的方式比较字符串,您可以使用 DbFunctions 来完成这项工作。

context.Counties.Where(x => EF.Functions.Like(x.Name, $"%{keyword}%")).ToList();

UPDATE to @Gert:更新到@Gert:

A part of the assumption in the question is incorrect.问题中的部分假设是不正确的。 string.Contains does NOT convert into a LIKE expression even though it USED to be the case in ef core versions <= 1.0 (I think). string.Contains不会转换为LIKE expression即使它在 ef 核心版本 <= 1.0 中曾经是这种情况(我认为)。

  • In SQLServer string.contains converts into CHARINDEX() , in oracle and sqlite into instr() which are case sensitive by default UNLESS db or column collation is defined otherwise ( Again, I don't know for postgresql ).SQLServer 中string.contains转换为CHARINDEX() ,在oraclesqlite 中转换为instr() ,默认情况下区分大小写,除非另外定义了 db 或列排序规则(同样,我不知道 postgresql )。
  • In all cases EF.Functions.Like() converts into a SQL LIKE expression which is case-insensitive by default unless db or column collation is defined otherwise.在所有情况下, EF.Functions.Like()转换为 SQL LIKE表达式,默认情况下该表达式不区分大小写,除非另外定义了 db 或列排序规则。

So yes it all goes down to collation but - correct me if I'm wrong - in a way the code can have an influence on the case-sensitive/insensitive search depending on which one of the above method you use.所以是的,这一切都归结为整理,但是 - 如果我错了,请纠正我 - 在某种程度上,代码可能会对区分大小写/不敏感的搜索产生影响,具体取决于您使用的上述方法之一。

Now, I might not be completely up to date but I don't think EF core migrations deal with DB collation naturally and unless you've already created the table manually you will end up with the default collation (case-sensitive for sqlite and I honestly don't know for the others).现在,我可能还没有完全了解最新情况,但我认为 EF 核心迁移不会自然地处理 DB 排序规则,除非您已经手动创建了表,否则最终会使用默认排序规则(对 sqlite 和我区分大小写)老实说不知道其他人)。

Getting back to the original question you have at least 2 options to perform this case-insensitive search if not 3 in a future release :回到最初的问题,您至少有 2 个选项来执行此不区分大小写的搜索,如果不是未来版本中的 3 个:

  1. Specify the column collation on creation using DbContext.OnModelCreating() using this trick使用此技巧使用 DbContext.OnModelCreating() 在创建时指定列排序规则
  2. Replace your string.Contains by EF.Functions.Like()EF.Functions.Like()替换你的string.Contains
  3. Or wait for a promising feature still in discussion : EF.Functions.Collate() function或者等待一个仍在讨论中的有前途的功能: EF.Functions.Collate()函数

My answer will concern NpgSQL.我的回答将涉及 NpgSQL。

  1. EF.Functions.Like() in PostgreSQL is case-sensitive, but you can use EF.Functions.ILike() extension method located in Npgsql.EntityFrameworkCore.PostgreSQL assembly . PostgreSQL 中的EF.Functions.Like()区分大小写,但您可以使用位于Npgsql.EntityFrameworkCore.PostgreSQL assembly 中的EF.Functions.ILike()扩展方法

  2. If you don't have reference to Entity Framework assembly in place where you build query, you can use combination ToLower() and Contains() methods, because Npgsql is able translate ToLower() method to correct SQL如果您在构建查询的地方没有引用实体框架程序集,您可以使用组合ToLower()Contains()方法,因为 Npgsql 能够转换ToLower()方法来更正 SQL

Example:例子:

context.Counties.Where(x => x.Name.ToLower().Contains(keyword.ToLower())).ToList();

About second method keep in mind: you may have performance problems and may encounter problems associated with encoding.关于第二种方法,请记住:您可能会遇到性能问题,并且可能会遇到与编码相关的问题。

Just try it :就试一试吧 :

You can Lower case field and search value您可以Lower case字段和搜索值

  context.Counties.Where(x => x.Name.ToLower().Contains(keyword.ToLower())).ToList();

Or you can Upper Case filed and search value或者您可以Upper Case并搜索值

context.Counties.Where(x => x.Name.ToUpper().Contains(keyword.ToUpper())).ToList();

IQueryable.Where is executed in the database, so it is most likely to be case insensitive. IQueryable.Where是在数据库中执行的,所以很可能是不区分大小写的。

IEnumerable.Where uses C# String.Contains , so it is case sensitive. IEnumerable.Where使用 C# String.Contains ,所以它区分大小写。

Read this answer: Returning IEnumerable vs. IQueryable阅读此答案:返回 IEnumerable 与 IQueryable

With Entity Framework Core 3.1 and MySQL / MariaDB providers you can manually set the case (in)sensitiveness with StringComparison.InvariantCultureIgnoreCase in the following way:使用 Entity Framework Core 3.1 和 MySQL / MariaDB 提供程序,您可以通过以下方式使用StringComparison.InvariantCultureIgnoreCase手动设置大小写(不)敏感度:

items = items.Where(i => 
    i.Name.Contains(value, StringComparison.InvariantCultureIgnoreCase));

The default behaviour seems to be case sensitive, however you can explicitly set it using StringComparison.InvariantCulture .默认行为似乎区分大小写,但是您可以使用StringComparison.InvariantCulture显式设置它。

For additional info, check out this post on my blog.有关更多信息,请查看这篇文章在我的博客。

I don't know if it works for previous versions as well (will check and update this answer accordingly).我不知道它是否也适用于以前的版本(将相应地检查并更新此答案)。

Use Explicit collation in a query在查询中使用显式排序规则

For example例如

var customers = context.Customers
.Where(c => EF.Functions.Collate(c.Name, "SQL_Latin1_General_CP1_CS_AS") == "John")
.ToList();

For more details see the msdn link有关更多详细信息,请参阅 msdn 链接

https://docs.microsoft.com/en-us/ef/core/miscellaneous/collations-and-case-sensitivity https://docs.microsoft.com/en-us/ef/core/miscellaneous/collat​​ions-and-case-sensitive

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM