我有一段在 EF Core 2.2 中作業的代碼,用于比較字串大小寫,如下所示。
public async Task<bool> DoesItemNumberExists(Guid revisionId, string itemNumber)
{
var doesExist = await _repository.AnyAsync(a => string.Equals(a.ItemNo, itemNumber, StringComparison.Ordinal) && a.SoqHeading_NP.SoqRevisionId == revisionId);
return doesExist;
}
我在 EF Core 5 中運行相同的代碼,但應用程式崩潰了。有什么幫助嗎?
下面是我得到的例外
The LINQ expression 'DbSet<SoqItem>()
.Where(s => s.IsDeleted == False)
.Join(
inner: DbSet<SoqHeading>()
.Where(s0 => s0.SoqRevisionId == __ef_filter__RevisionId_0 && s0.IsDeleted == False),
outerKeySelector: s => EF.Property<Nullable<Guid>>(s, "SoqHeadingId"),
innerKeySelector: s0 => EF.Property<Nullable<Guid>>(s0, "Id"),
resultSelector: (o, i) => new TransparentIdentifier<SoqItem, SoqHeading>(
Outer = o,
Inner = i
))
.Any(s => string.Equals(
a: s.Outer.ItemNo,
b: __itemNumber_0,
comparisonType: Ordinal) && s.Inner.SoqRevisionId == __revisionId_1)' 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.
uj5u.com熱心網友回復:
因為StringComparison.Ordinal陳述句不能轉換為SQL查詢。
您應該在沒有讀取資料的情況下讀取資料StringComparison.Ordinal,并且當資料從SQL應用程式記憶體讀取并到達應用程式記憶體時,您就可以使用StringComparison.Ordinal.
public async Task<bool> DoesItemNumberExists(Guid revisionId, string itemNumber)
{
var selectedRows = await _dbContext.YourTable.Where(a => a.ItemNo == itemNumber && a.SoqHeading_NP.SoqRevisionId == revisionId).ToListAsync();
return selectedRows.Any(a => string.Equals(a.ItemNo, itemNumber, StringComparison.Ordinal));
}
微軟參考:
在 3.0 之前,當 EF Core 無法將作為查詢一部分的運算式轉換為 SQL 或引數時,它會自動在客戶端上評估該運算式。默認情況下,客戶端對潛在昂貴運算式的評估僅觸發警告。
新行為 從 3.0 開始,EF Core 僅允許在Select()客戶端上評估頂級投影(查詢中的最后一次呼叫)中的運算式。When查詢的任何其他部分中的運算式不能轉換為 SQL 或引數,會引發例外。
為什么?
查詢的自動客戶端評估允許執行許多查詢,即使它們的重要部分無法翻譯。這種行為可能會導致意外的和潛在的破壞性行為,這些行為可能只會在生產中變得明顯。例如,Where()呼叫中無法轉換的條件可能會導致表中的所有行都從資料庫服務器傳輸,并在客戶端上應用過濾器。如果該表在開發中僅包含幾行,則這種情況很容易被發現,但當應用程式轉移到生產時,該表可能包含數百萬行,這種情況會受到嚴重打擊。在開發程序中,客戶評估警告也很容易被忽視。
除此之外,自動客戶端評估可能會導致問題,在這些問題中,改進特定運算式的查詢翻譯會導致版本之間出現意外的破壞性更改。
uj5u.com熱心網友回復:
區分大小寫和排序規則在檔案、檔案、排序規則和大小寫敏感度中進行了解釋
這不是 EF Core 5 錯誤。查詢總是無法轉換為 SQL,但 EF Core 2 通過在記憶體中加載所有內容然后在沒有索引的情況下匹配客戶端上的記錄來掩蓋這一點。EF Core 的第一個版本中的 LINQ 翻譯非常有限,甚至GROUP BY無法翻譯。物體框架會在這種情況下拋出。不過,為了避免破壞在 EF 6 中完美運行的代碼,EF Core 1 和 2 使用了客戶端評估:他們將可能的內容轉換為 SQL,然后將資料加載到記憶體中的客戶端上,并使用LINQ 到物件。
這意味著,如果您想計算 100K 行的 SUM,EF Core 1-2 將在記憶體中加載所有 100K 行并繼續將這些值一一相加。不要介意將兩個表連接起來,每個表有 1000 行 - 這是 100 萬次比較。
即使在 EF Core 2.1 中,客戶端評估也會生成運行時警告并且可以完全禁用。在 EF Core 3.1 客戶端評估被完全禁用。
為了讓您的查詢正常作業,不要嘗試強制使用大小寫或排序規則。只需使用簡單的等式:
var itemExists=context.Products.Any(a=>a.ItemNumber == itemNumber &&
a.SoqHeading_NP.SoqRevisionId == revisionId);
這將被翻譯成WHERE ItemNumber=@itemNumber && SoqHeading_NP.SoqRevisionId = @revisionId. 查詢將使用任何覆寫ItemNumber和SoqRevisionId列的索引來盡快生成結果。
用于相等匹配的排序規則是列的排序規則。如果區分大小寫,您將獲得區分大小寫的匹配。如果沒有,你區分在敏感匹配。索引是使用列的排序規則構建的,因此如果您嘗試使用不同的排序規則進行匹配,您將阻止服務器使用任何索引。
如果你想在不同的查詢中使用不同的大小寫匹配并且仍然使用索引,你需要為每個案例創建不同的索引。你如何做到這一點取決于資料庫
- 在 SQL Server 中,不區分大小寫是最常見的選項。要同時使用該搜索和區分大小寫的搜索,您可以使用二進制(因此區分大小寫)排序規則創建一個計算列的索引,例如:
alter table Table1 add ItemNumberCS as COLLATE ..._BIN;
create index IX_Table1_ItemNumberCS on Table1 (ItemNumberCS);
區分大小寫的查詢應該使用該ItemNumberCS列。
- 在 PostgreSQL 中,所有排序規則都區分大小寫。但是,從 v12 開始,您可以創建自定義排序規則并在計算索引運算式中使用它。要使用區分在敏感的搜索,你可以創建一個不區分大小寫的整理和指數如:
CREATE COLLATION case_insensitive (
provider = icu,
locale = 'und-u-ks-level2',
deterministic = false
);
CREATE INDEX IX_Table1_ItemNumberCI ON Table1 (title COLLATE "case_insensitive");`
LINQ 查詢不必更改。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/317616.html
