我在LINQ to Entities中有以下查询:
var query = from p in db.Products
where p.Price > 10M
select p;
在这一点上,查询还没有执行,我想编写一个基于以下条件返回true/false的查询:
return query.Any(p => p.IsInStock &&
(p.Category == "Beverage" ||
p.Category == "Other"));
这可以很好地工作;但是,我希望从我的代码中获得一些重用。我有很多方法需要根据类别是Beverage还是Other进行过滤,所以我尝试创建一个委托:
Func<Product, bool> eligibleForDiscount = (product) => product.Category == "Beverage" || product.Category == "Other";
我想用委托替换内联检查:
return query.Any(p => p.IsInStock && eligibleForDiscount(p));
这给了我一个错误,说LINQ to Entities不支持Invoke。为什么我不能用内联代码代替这样的委托,有没有其他方法可以实现重用呢?
发布于 2012-05-16 15:48:13
回想一下,在幕后,Linq-to-{DATABASE}
只是将您生成的IQueryable
转换成Sql。
您不能像那样内联代码,因为Invoke
(当您调用Func
或Action
时实际调用的方法)没有一致的方法将其转换为SQL语句(您可以在其中执行任何操作)。
也就是说,您可以通过拆分部件来重用部件:
var query = from p in db.Products
where p.Price > 10M
select p;
query = query.Where(p => p.IsInStock);
query = query.Where(p => p.Category == "Beverage" || p.Category == "Other");
return query.Any();
这两种方法都可以放入接受IQueryable<Product>
并返回相同内容(但经过过滤)的方法中。然后你就可以尽情地重用了!
发布于 2012-05-16 15:52:42
问题是,IQueryable
需要生成一个传递给关系数据库的SQL表达式,并且当它所拥有的全部都是一个不透明的谓词时,它无法做到这一点。
一种显而易见但效率低下的方法是重写查询,如下所示:
return query.Where(p => p.IsInStock).AsEnumerable().Any(eligibleForDiscount);
一种不那么微不足道的方法如下:
bool GotEligible(Expression<Func<Product,bool>> pred) {
return query.Where(p => p.IsInStock).Any(pred);
}
请注意,此方法如何接受谓词表达式,而不是谓词。现在,它对EF是透明的,并且可以毫无问题地转换为SQL查询。
发布于 2016-01-11 10:25:17
只要您坚持使用IQueryable,就可以在函数中保留可重用的查询。
public IQueryable<Product> EligibleForDiscount(IQueryable<Product> products)
{
return products.Where(p => product.Category == "Beverage" ||
product.Category == "Other");
}
现在像调用任何其他函数一样调用它:
IQueryable<Product> query = (from p in db.Products
where p.Price > 10M
select p);
query = EligibleForDiscount(query);
https://stackoverflow.com/questions/10621938
复制