簡體   English   中英

為什么一個查詢有效而另一個無效?

[英]Why one query works and not the other?

我正在使用幫助器方法根據用戶訪問權限預過濾我的所有查詢。

假設方法簽名為:

public IQueryable<Client> GetAllClients()

使用LINQ時為什么這樣做:

IQueryable<Client> allItems = GetAllClients();
return (from item in allItems
where item.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)
select item).FirstOrDefault();

但不是這個:

return (from item in GetAllClients() 
    where item.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)
    select item).FirstOrDefault();

我可以做第一個,但是離開LINQ幾年之后,理解這個問題的原因會很好。

不工作我的意思是選項2給出了這個例外:

EntityFramework.SqlServer.dll中發生了'System.NotSupportedException'類型的第一次機會異常

附加信息:LINQ to Entities無法識別方法'System.Linq.IQueryable`1 [typename] GetAllClients()'方法,並且此方法無法轉換為商店表達式。

客戶端是存儲在數據庫中的數據類型。 我正在為常用查詢創建實體框架數據模型的方法,並且由於多租戶設計具有由數據類型定義的安全訪問,我想在數據訪問級別進行過濾。

這里的問題是可查詢層正在嘗試將方法調用GetAllClients轉換為查詢,而不是使用GetAllClients的返回值作為查詢源。 語法上的欺騙,是的,但也完全是預期的。

之所以發生這種情況,是因為與IEnumerable不同, IQueryable對象實際上提供了可用於將(在這種情況下)轉換為SQL的元代碼。 由於大多數C#方法都沒有SQL等價物,並且無法以相同的方式掃描編譯方法的元序列,因此當這些框架遇到無法翻譯的內容時,它們就會出錯。

請注意,避免大部分問題的一種方法是避免使用Linq styntax,而是進行方法調用,這將稍微減少欺騙:

return GetAllClients()
    .Where(item => item.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)
    .FirstOrDefault();

您正在從過濾器方法返回IQueryable<Client> C#編譯器識別它並自動將 return語句中的lambda表達式轉換為它的表達式樹表示。 (自動轉換是IQueryable的整個延遲執行功能如何工作)。

在第一種情況下, return item from allItems你會得到一個這樣的表達式樹:

Call: Queryable.Select(Constant: allItems, LambdaExpression: predicate)

return item from GetAllClients()的第二種情況下return item from GetAllClients()你得到這個:

Call: Queryable.Select(Call: GetAllClients, LambdaExpression: predicate)

請注意,Queryable.Select的第一個參數是不同的! 在第二種情況下,編譯器通過將其存儲在表達式樹中來延遲執行GetAllClients的調用。 當該表達式樹最終到達EF的SQL轉換器時,EF不知道如何將對C# GetAllClients函數的調用更改為有效的SQL。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM