Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/python-2.7/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# LINQ to实体不支持调用_C#_Linq To Entities - Fatal编程技术网

C# LINQ to实体不支持调用

C# LINQ to实体不支持调用,c#,linq-to-entities,C#,Linq To Entities,我在LINQ to实体中有以下查询: var query = from p in db.Products where p.Price > 10M select p; 此时查询尚未执行,我想编写一个查询,根据某些条件返回true/false: return query.Any(p => p.IsInStock && (p.Category == "Beverage" ||

我在LINQ to实体中有以下查询:

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"));
这很好用;然而,我想从我的代码中得到一些重用。我有许多方法需要根据类别是饮料还是其他进行过滤,因此我尝试创建一个代理:

Func<Product, bool> eligibleForDiscount = (product) => product.Category == "Beverage" || product.Category == "Other";
return query.Any(p => p.IsInStock && eligibleForDiscount(p));

这给了我一个错误,即LINQtoEntities不支持调用。为什么我不能用内联代码代替这样的委托,有没有其他方法可以实现重用?

回想一下,在后台
Linq to-{DATABASE}
只是将您生成的
IQueryable
转换为Sql

您不能这样内联代码,因为
调用
(当您调用
函数
操作
时实际调用的方法)没有一致的方法将其转换为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
,并返回相同的结果(但经过过滤)。然后你可以随心所欲地重复使用

问题在于,
IQueryable
需要生成一个SQL表达式来传递给RDBMS,而当它只有一个不透明的谓词时,它就不能这样做

显而易见但效率低下的方法是按如下方式重写查询:

return query.Where(p => p.IsInStock).AsEnumerable().Any(eligibleForDiscount);
bool GotEligible(Expression<Func<Product,bool>> pred) {
    return query.Where(p => p.IsInStock).Any(pred);
}
一个不那么琐碎的方法如下:

return query.Where(p => p.IsInStock).AsEnumerable().Any(eligibleForDiscount);
bool GotEligible(Expression<Func<Product,bool>> pred) {
    return query.Where(p => p.IsInStock).Any(pred);
}
bool-gotQualified(表达式pred){
返回query.Where(p=>p.IsInStock).Any(pred);
}

请注意,此方法如何使用谓词表达式而不是谓词。现在它对EF是透明的,可以毫无问题地转换为SQL查询。

只要您坚持使用IQueryable,就可以在函数中保留可重用的查询

  public IQueryable<Product> EligibleForDiscount(IQueryable<Product> products)
  {
       return products.Where(p => product.Category == "Beverage" || 
                                  product.Category == "Other");
  }
public IQueryable deligiblefordiscount(IQueryable产品)
{
退货产品。其中(p=>product.Category==“饮料”|
产品类别=“其他”);
}
现在像调用任何其他函数一样调用它:

  IQueryable<Product> query = (from p in db.Products
                               where p.Price > 10M
                               select p);

  query = EligibleForDiscount(query);
IQueryable查询=(来自db.Products中的p
其中p.价格>10M
选择p);
query=EligibleForDiscount(查询);

考虑到这个问题没有一个被接受的答案,我不知道这个PredicateBuilder是什么,我不认为这个问题是重复的。所以你的建议是有一个方法,它可以IQueRead并且返回IQueRead而不是一个委托。我猜它们做的事情是一样的:)它们做的事情完全一样,而且它的可重用性更高……采用IQueryable和返回IQueryable的方法和函数真的很强大。作为额外的好处,这也可以被做成一个扩展方法,提供定制的光滑查询。WhereIsAnyCategory(“饮料”、“其他”)(或query.WhereBeverageOrOther())在IQueryable接口上键入语法。顺便说一句,您想去掉
任何
条款中的
(p)
,可能您的意思是
gotQualified
;)