我有一種使用 DbContext 和 EF Core 以及以下代碼檢索餐廳表結果的方法:
public IEnumerable<Restaurant> GetRestaurantByName(string? name = null)
{
if (string.IsNullOrEmpty(name))
{
return _dbContext.Restaurants;
}
else
{
return _dbContext.Restaurants
.Where(r => r.Name.ToLower().Contains(name.ToLowerInvariant()));
}
}
問題是當我嘗試使用r.Name.ToLowerInvariant()而不是r.Name.ToLower()捕獲具有以下詳細資訊的例外時:
InvalidOperationException:無法翻譯 LINQ 運算式 'DbSet() .Where(r => r.Name.ToLowerInvariant().Contains(__ToLowerInvariant_0))'。
我喜歡了解幕后的確切原因和邏輯。
uj5u.com熱心網友回復:
我喜歡了解幕后的確切原因和邏輯。
您需要了解 EFC 是一個翻譯器。它查看您構建的 LINQ 查詢并將其逐個轉換為 SQL,然后運行 ??SQL
當你說:
context.Persons.Where(p => p.Name == "SMITH")
它成為了:
SELECT * FROM persons WHERE name = 'SMITH'
當你說:
context.Persons.Where(p => p.Name.ToLower() == "SMITH")
它成為了:
SELECT * FROM persons WHERE LOWER(name) = 'SMITH'
無論如何,這兩者的功能可能相同。C# 區分大小寫,但 SQL Server 可能不區分(默認情況下它使用不敏感的排序規則),所以即使 C# 看起來像廢話:
Name.ToLower() == "SMITH" //this would never return anything in C#
不敏感模式下的 SQLServer 將運行它并回傳結果:
LOWER(name) = 'SMITH' --SQLServer will return
您必須意識到您的 C# 被翻譯成另一種語言并根據該語言的規則運行,而不是 C#
如果您想查看查詢結果,請不要運行它:
var q = context.Persons.Where(p => p.Name.ToLower() == "SMITH")
//.ToList() //don't run it
現在指向q除錯器并檢查 DebugView - EFC 將告訴您它生成的 SQL(EFC5 功能)
現在記住我們說過這是一個翻譯練習——EFC 只能翻譯它所知道的——這是針對 sql server 的,不同的供應商翻譯不同。如果你使用一個它不知道的函式,比如 ToLowerInvariant,你會得到一個錯誤。在 Microsoft(或撰寫您正在使用的提供程式的人)中,沒有人坐下來想出一種以有意義的方式將 ToLowerInvariant 轉換為 SQL 的方法。
如果你讓你的 LINQ 太復雜,你也會得到一個錯誤;您必須找到另一種方法來撰寫可以翻譯的 LINQ,或者接受打擊并將(?大量)資料下載到 C# 中并在那里處理它
uj5u.com熱心網友回復:
這是我一直困擾且難以除錯的問題。當在 DB 中使用函式時,where 函式受到某種限制。
這是一個例子:
DataContext.Products.Where(product => product.Count > 5); \\ This works fine
DataContext.Products.Where(product => product.Name == "Mac".ToLower()); \\ Also works fine because "Mac" will be converted into "mac" before being inserted in the query, so it's value is handled in the app, not db server, and will be in the query as a static value.
\\ Now here let's make a call on the product
DataContext.Products.Where(product => product.Name.ToLowerInvariant() == "mac"); \\ Throws an exception because function ToLowerInvariantis not registered in the DB, so the DB doesn't know how to call this function or handle it.
如果您嘗試在這些對 DB 起作用的 where 陳述句中呼叫函式,也會發生同樣的事情
public bool HasItems(Product prod) => prod.Count > 0;
DataContext.Products.Where(prod => HasItems(Prod)); // Also throws the same exception cause the function is again is not mapped to any DB Function.
如果您嘗試將 HasItems 設定為僅作為 Getter 屬性怎么辦?
public class Product {
public int Count {get;set;}
public bool HasItems => Count > 0;
}
DataContext.Products.Where(prod => prod.HasItems);
// Will throw an exception, cause migration won't register HasItems as computed column, so this property is not known in the DB and it doesn't know how to get its value.
因此,只要您嘗試呼叫的函式或列未在 DB Server 中注冊,并且查詢將在 DB Server 內部作業,它就會拋出例外。但是,如果您對應用程式中可用的資料使用相同的查詢,它們就可以正常作業。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/455319.html
下一篇:LINQ連接查詢目標具有串列欄位
