?
可以使用'StringComparison'嗎?
在數(shù)據(jù)庫查詢操作中,不可避免去考慮字母大小寫的問題,比如要在Movie表中查找“X-Men”這部電影,為了不區(qū)分字母大小寫,按照Linq to memory的習慣,可能會寫出如下代碼:
DbContext.DbSet<Movie>
.Where(item => string.Equals(item.Title, "X-Men", StringComparison.InvariantCultureIgnoreCase)
但是上述代碼執(zhí)行會報錯,提示?'StringComparison'參數(shù)不支持。
InvalidOperationException: The LINQ expression 'DbSet<Movie>() .Where(m => string.Equals( a: m.Genre, b: __MovieGenre_0, comparisonType: InvariantCultureIgnoreCase))' could not be translated. Additional information: Translation of the 'string.Equals' overload with a 'StringComparison' parameter is not supported. See https://go.microsoft.com/fwlink/?linkid=2129535 for more information. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
怎么解決這個問題呢?如果你用的是SQL server或MySQL,那么很簡單,去掉“StringComparison.InvariantCultureIgnoreCase”這個參數(shù)就可以了,因為他們是默認大小寫不敏感的。如果用的是大小寫敏感的數(shù)據(jù)庫,比如PostgreSQL,就需要做一些特殊處理了,后面會講到。
對于這類問題有一個暴力的解決方法,就是按報錯提示的那樣在查詢客戶端做篩選:
DbContext.DbSet<Movie> .ToList() .Where(item => string.Equals(item.Title, "X-Men", StringComparison.InvariantCultureIgnoreCase)
這樣做的本質(zhì)是返回所有的Movie,然后在內(nèi)存中做Title匹配查詢(Linq to memory),而不是在DB中做Title的匹配查詢,所以不會報?'StringComparison'參數(shù)不支持的錯誤。這種方法在絕大多數(shù)場景下是不推薦的,因為 1. 性能差,查詢是在內(nèi)存中不是在DB中,2. 占用內(nèi)存,返回了整張表
?
為什么不能使用'StringComparison'?
前面講到有的數(shù)據(jù)庫是默認大小寫不敏感的:SQL server,MySQL;有的數(shù)據(jù)庫是默認大小寫敏感的:PostgreSQL。那么數(shù)據(jù)庫中大小寫敏感與否是由什么控制的呢,排序規(guī)則(Collation,一組規(guī)則,用于確定文本值的排序和相等性比較方式,可以在數(shù)據(jù)庫,表和列上創(chuàng)建排序規(guī)則,排序規(guī)則是隱式繼承的,比如在數(shù)據(jù)庫上創(chuàng)建了排序規(guī)則,沒有在表上創(chuàng)建排序規(guī)則,那么表會默認使用數(shù)據(jù)庫的排序規(guī)則,列同理)。因為EF core不知道數(shù)據(jù)庫,表,列支持/應(yīng)用了什么樣的排序規(guī)則,所以'StringComparison'是沒有意義的,EF core會將? string.Equals 轉(zhuǎn)化成數(shù)據(jù)庫的相等( = )操作,由數(shù)據(jù)庫根據(jù)列上應(yīng)用的排序規(guī)則來決定是否區(qū)分大小寫。
?
如何在查詢中設(shè)置區(qū)分大小寫與否?
既然區(qū)分大小寫是由排序規(guī)則決定的,我們可以通過在查詢中指定排序規(guī)則的方式來來設(shè)置是否區(qū)分大小寫,例如SQL Server默認是不區(qū)分大小寫的,我們可以通過 EF.Functions.Collate 來指定一個大小寫敏感的排序規(guī)則"SQL_Latin1_General_CP1_CS_AS"來達到精確匹配的目的
DbContext.DbSet<Movie> .Where(m => EF.Functions.Collate(item.Title, "SQL_Latin1_General_CP1_CS_AS") == "X-Men")
但是這種顯示指定排序規(guī)則的方法也不是非常推薦的,因為他會導(dǎo)致索引匹配失敗,進而影響查詢性能。索引隱式繼承列上的排序規(guī)則,當顯示指定的排序規(guī)則和創(chuàng)建索引時指定的排序規(guī)則(PostgreSQL支持在創(chuàng)建索引時指定排序規(guī)則)或列的排序規(guī)則不一致時,會導(dǎo)致索引匹配失敗,進而導(dǎo)致查詢不能應(yīng)用索引,這也是EF Core沒有將'StringComparison'轉(zhuǎn)換成排序規(guī)則的另一個原因。
因此一個相對完善的解決方案是,根據(jù)業(yè)務(wù)模型在列上指定合適的排序規(guī)則,而不是在代碼中設(shè)置。如果數(shù)據(jù)庫支持在列上創(chuàng)建多個索引,你也可以用顯示指定排序規(guī)則的方式根據(jù)業(yè)務(wù)場景切換排序規(guī)則來匹配正確的索引。
?
參考文檔:
https://learn.microsoft.com/en-us/ef/core/miscellaneous/collations-and-case-sensitivity
https://learn.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-ver16文章來源:http://www.zghlxwxcb.cn/news/detail-411835.html
https://www.postgresql.org/docs/current/collation.html文章來源地址http://www.zghlxwxcb.cn/news/detail-411835.html
到了這里,關(guān)于Entity Framework Core 大小寫敏感處理的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!