LINQ异常:“不支持使用本地集合的查询。”但不使用本地收藏

时间:2010-12-11 00:44:55

标签: linq exception datacontext

使用AdventureWorks数据库的Products表作为示例,我创建了一个DBML并扩展了DataContext的属性以包含一个新属性:

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

Products属性是生成的DataContext的一部分,我所做的就是从表中添加一个&lt; Product&gt;所以它返回一个IQueryable。

现在,当尝试像这样查询时出现问题(愚蠢的例子,但应该显示问题):

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

迭代此查询会导致“不支持使用本地集合进行查询”异常。我不明白为什么在没有使用本地集合时会抛出该错误。如果我针对普通的Products表(Table<Product>)运行它:

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

......它运作正常。唯一的区别是我在Table<Product>添加了一个位置并将其作为IQueryable<Product>返回。

有人有什么想法吗?

2 个答案:

答案 0 :(得分: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 :(得分: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在查询转换期间过于急切地发出子查询,然后为主查询进行第二次往返。

相关问题