2010-12-11 55 views
2

使用AdventureWorks數據庫的Products表爲例,我創建了一個DBML和擴展在DataContext的特性,包括一個新的屬性:LINQ異常:「不支持查詢與本地集合。」但不使用本地收集

 
partial class AdventureWorksDataContext 
{ 
    public IQueryable<Product> FinishedProducts 
    { 
    get { return Products.Where(p => p.FinishedGoodsFlag); } 
    } 
} 

產品屬性的一部分生成的DataContext和我所做的一切都是從表<產品>添加一個位置,因此它返回一個IQueryable。現在

,問題就來嘗試查詢像這樣當(愚蠢的例子,但一個應該顯示的問題):

var queryFinishedProducts = datacontext.FinishedProducts.Where(fp => fp.ProductID == datacontext.FinishedProducts.Max(p => p.ProductID));

迭代這個查詢結果「與當地館藏查詢是不支持「的例外。我不明白爲什麼當沒有使用本地集合時會拋出這個錯誤。如果我運行它以與普通產品表(這是一個Table<Product>):

var queryProducts = datacontext.FinishedProducts.Where(fp => fp.ProductID == datacontext.Products.Max(p => p.ProductID));

...它工作正常。唯一的區別是我添加了一個Where到Table<Product>並將其作爲IQueryable<Product>返回。

任何人有任何想法?

+1

已完成產品屬性? 「獲得」在哪裏? – 2010-12-11 04:30:25

+0

是的,這是一個屬性。對不起,我會添加清晰度。 – Mike 2010-12-12 07:27:58

+0

看起來也許SQL生成器無法判斷FinishedProducts查詢中使用的'Products'是否與查詢的其餘部分來自同一個'DataContext'。 – Gabe 2010-12-12 07:47:58

回答

0

這裏有一個方法,應該工作:

var max = datacontext.FinishedProducts.Max(p => p.ProductID); 
var queryFinishedProducts = datacontext.FinishedProducts 
             .Where(fp => fp.ProductID == max); 

或者假設ProductID是獨一無二的請嘗試重寫你的查詢,如下所示:

var queryProducts = datacontext.FinishedProducts 
           .OrderByDescending(p => p.ProductID) 
           .First(); 
+1

感謝您的回覆,但是我正在尋找更多的原因,爲什麼LINQ會以不同的方式處理基本相同的查詢。查詢實際上只是一個更大問題的例子,因爲lambda能夠使用本質上是子SELECT的東西。 – Mike 2010-12-11 01:03:20

+0

@Mike:我認爲不同之處在於'產品'不僅僅是'IQueryable ',它是'表'。 – 2010-12-11 01:21:06

+0

我用Reflector挖入Table和DataQuery類的內部,Table只是實現了CreateQuery方法,並且每當使用擴展方法時就返回一個DataQuery。話雖如此,那麼Products.Where(p => p)應該等於返回相同語句的屬性,這就是示例所顯示的內容。這就是我不明白的是如何使用Products屬性傳回IQueryable是不同的。 – Mike 2010-12-11 03:52:49

0

我能重現此問題。這裏有幾種類型的反射鏡:

System.Data.Linq.SqlClient.SqlBinder.Visitor 
System.Data.Linq.SqlClient.SqlVisitor 

基於這個堆棧跟蹤。

at System.Data.Linq.SqlClient.SqlBinder.Visitor.ConvertToFetchedSequence(SqlNode node) 
at ..SqlBinder.Visitor.VisitAlias(SqlAlias a) 
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node) 
at ..SqlVisitor.VisitSource(SqlSource source) 
at ..SqlBinder.Visitor.VisitSelect(SqlSelect select) 
at ..SqlVisitor.Visit(SqlNode node) 
at ..SqlBinder.Visitor.VisitAlias(SqlAlias a) 
at ..SqlVisitor.Visit(SqlNode node) 
at ..SqlVisitor.VisitSource(SqlSource source) 
at ..SqlBinder.Visitor.VisitSelect(SqlSelect select) 
at ..SqlVisitor.Visit(SqlNode node) 
at ..SqlVisitor.VisitSequence(SqlSelect sel) 
at ..SqlVisitor.VisitScalarSubSelect(SqlSubSelect ss) 
at ..SqlVisitor.VisitSubSelect(SqlSubSelect ss) 
at ..SqlBinder.Visitor.VisitSubSelect(SqlSubSelect ss) 

我不知道爲什麼Table<T>類型的屬性是區別對待的類型不是IQueryable<T>甚至ITable<T>的屬性。該財產的實施並不重要,返回類型的事項。


IQueryable<T>類型的屬性被肯定處理不同於IQueryable<T>

IQueryable<Customer> query1 = 
    myDC.Customers.Where(c => c.ID == myDC.CoolCustomers.Max(c2 => c2.ID)); 

IQueryable<Customer> query2 = 
    myDC.Customers.Where(c => c.ID == myDC.Customers.Where(c2 => c2.Flag).Max(c2 => c2.ID)); 

IQueryable<Customer> subQuery = myDC.CoolCustomers; 
IQueryable<Customer> query3 = 
    myDC.Customers.Where(c => c.ID == subQuery.Max(c2 => c2.ID)); 

QUERY1表現出原來的行爲(異常,本地序列)類型的局部範圍的變量。

query2生成此sql - 不太理想。

SELECT [t0].[ID], [t0].[Flag] 
FROM [Customer] AS [t0] 
OUTER APPLY (
    SELECT MAX([t1].[ID]) AS [value] 
    FROM [Customer] AS [t1] 
    WHERE [t1].[Flag] = 1 
    ) AS [t2] 
WHERE [t0].[ID] = [t2].[value] 

QUERY3過度急切地詢問翻譯過程中發出的子查詢,然後進行主查詢第二個往返。

+0

感謝您深入LINQ框架!我只是希望我明白爲什麼它被區別對待。我會開始挖掘這些課程,看看我還能找到什麼。真的希望這不是第一次出現,似乎任何大型項目都可能對錶格屬性進行預過濾。 – Mike 2010-12-11 09:14:49