【发布时间】:2010-09-22 12:50:09
【问题描述】:
我遇到了一个场景,其中 LINQ to SQL 的行为非常奇怪。我想知道我是否做错了什么。但我认为它很有可能是一个错误。
下面粘贴的代码不是我的真实代码。这是我为这篇文章创建的简化版本,使用的是 Northwind 数据库。
一点背景知识:我有一个方法,它采用Product 的IQueryable 和一个“过滤器对象”(我将在稍后描述)。它应该基于“过滤器对象”在IQueryable 上运行一些“Where”扩展方法,然后返回IQueryable。
所谓的“过滤对象”就是一个System.Collections.Generic.List这个结构的匿名类型:{ column = fieldEnum, id = int }
fieldEnum 是Products 表中我可能希望用于过滤的不同列的枚举。
与其进一步解释我的代码是如何工作的,不如看看它会更容易。很容易理解。
enum filterType { supplier = 1, category }
public IQueryable<Product> getIQueryableProducts()
{
NorthwindDataClassesDataContext db = new NorthwindDataClassesDataContext();
IQueryable<Product> query = db.Products.AsQueryable();
//this section is just for the example. It creates a Generic List of an Anonymous Type
//with two objects. In real life I get the same kind of collection, but it isn't hard coded like here
var filter1 = new { column = filterType.supplier, id = 7 };
var filter2 = new { column = filterType.category, id = 3 };
var filterList = (new[] { filter1 }).ToList();
filterList.Add(filter2);
foreach(var oFilter in filterList)
{
switch (oFilter.column)
{
case filterType.supplier:
query = query.Where(p => p.SupplierID == oFilter.id);
break;
case filterType.category:
query = query.Where(p => p.CategoryID == oFilter.id);
break;
default:
break;
}
}
return query;
}
所以这里有一个例子。假设 List 包含两个这种匿名类型的项目,{ column = fieldEnum.Supplier, id = 7 } 和 { column = fieldEnum.Category, id = 3}。
运行上述代码后,IQueryable 对象的底层 SQL 查询应包含:
WHERE SupplierID = 7 AND CategoryID = 3
但实际上,在代码运行之后,得到执行的 SQL 是
WHERE SupplierID = 3 AND CategoryID = 3
我尝试将query 定义为属性并在设置器上设置断点,以为我可以捕捉到不应该发生的变化。但据说一切都很好。因此,我只是在每个命令之后检查底层 SQL。我意识到第一个 Where 运行良好,query 保持良好(意思是 SupplierID = 7)直到 foreach 循环第二次运行之后。在oFilter 成为第二个匿名类型项目而不是第一个之后,“查询”SQL 更改为Supplier = 3。所以这里必须发生的事情是,LINQ to SQL 不仅记住了Supplier 应该等于 7,还记住了 Supplier 应该等于 oFilter.id。但是oFilter是foreach循环的单个项目的名称,它在迭代之后意味着不同的东西。
【问题讨论】:
-
Brian 已经解决了这个错误(它与表达式的评估时间有关),但请注意,初始查询末尾的“.AsQueryable()”是不必要的,因为 db.Products是 Table
,它已经是 IQueryable 。
标签: linq linq-to-sql