C# 实体框架核心-在Queryable中使用扩展方法

C# 实体框架核心-在Queryable中使用扩展方法,c#,entity-framework,entity-framework-core,C#,Entity Framework,Entity Framework Core,我有以下疑问: db.Users.AsQueryable() .Where(u => u.Id = userResolver.LoggedUserId() && u.Packages.Where(p => p.StatusId == (int)PackageStatus.InProgress || p.StatusId == (int)PackageStatus.Delivered ||

我有以下疑问:

db.Users.AsQueryable()
    .Where(u => u.Id = userResolver.LoggedUserId() && u.Packages.Where(p => 
            p.StatusId == (int)PackageStatus.InProgress ||
            p.StatusId == (int)PackageStatus.Delivered ||
            p.StatusId == (int)PackageStatus.Shipped ||
            p.StatusId == (int)PackageStatus.Waiting) 
        .Sum(p => p.Price) > u.MaxCredit)
    .ToList()
我试图实现的是将所有包状态检查分组到一个扩展方法。诸如此类:

db.Users.AsQueryable()
        .Where(u => u.Id = userResolver.LoggedUserId() &&
             u.Packages.Where(p => p.IsShippedOrInProgress())
            .Sum(p => p.Price) > u.MaxCredit)
        .ToList()


 //This is the extension method
 public static bool IsShippedOrInProgress(this Package p) {
    return p.StatusId == (int)PackageStatus.InProgress ||
           p.StatusId == (int)PackageStatus.Delivered ||
           p.StatusId == (int)PackageStatus.Shipped ||
           p.StatusId == (int)PackageStatus.Waiting)
 }

当我查看第一个示例中生成的sql查询时,一切似乎都正常,但当我使用第二种方法时,检查状态的查询部分不存在。

我尝试在记事本中编写此内容。所以可能会有错误。请在评论中告诉我

public static Expression<Func<Package,bool>> IsShippedOrInProgress() {

    // Compose the expression tree that represents the parameter to the predicate.  
    ParameterExpression p = Expression.Parameter(typeof(Package), "p");  

    // Compose left side of the expression i.e `p.StatusId`
    Expression left = Expression.Call(p, typeof(Package).GetProperty("StatusId"));  

    // Compose right side of the expression i.e `(int)PackageStatus.InProgress` etc.
    Expression exprInProgress = Expression.Constant((int)PackageStatus.InProgress);  
    Expression exprDelivered = Expression.Constant((int)PackageStatus.Delivered);  
    Expression exprShipped = Expression.Constant((int)PackageStatus.Shipped);  
    Expression exprWaiting = Expression.Constant((int)PackageStatus.Waiting);  

    // Compose left equals right side
    Expression e1 = Expression.Equal(left, exprInProgress);  
    Expression e2 = Expression.Equal(left, exprDelivered);  
    Expression e3 = Expression.Equal(left, exprShipped);  
    Expression e4 = Expression.Equal(left, exprWaiting);  

    //Compose `p.StatusId == (int)PackageStatus.InProgress ||
    //       p.StatusId == (int)PackageStatus.Delivered ||
    //       p.StatusId == (int)PackageStatus.Shipped ||
    //       p.StatusId == (int)PackageStatus.Waiting`
    Expression orConditions = Expressions.OrElse(Expression.OrElse(Expression.OrElse(e1,e2),e3),e4);

    //Compose `p => 
    //        p.StatusId == (int)PackageStatus.InProgress ||
    //        p.StatusId == (int)PackageStatus.Delivered ||
    //        p.StatusId == (int)PackageStatus.Shipped ||
    //        p.StatusId == (int)PackageStatus.Waiting`
    return Expression.Lambda<Func<Package, bool>>(orConditions, new ParameterExpression[] { p })); 

}
公共静态表达式IsShippedOrInProgress(){
//组合表示谓词参数的表达式树。
ParameterExpression p=表达式参数(typeof(Package),“p”);
//合成表达式的左侧,即'p.StatusId'`
Expression left=Expression.Call(p,typeof(Package).GetProperty(“StatusId”);
//编写表达式的右侧,即`(int)PackageStatus.InProgress`等。
Expression exprInProgress=Expression.Constant((int)PackageStatus.InProgress);
exprDelivered表达式=Expression.Constant((int)PackageStatus.Delivered);
exprShipped=Expression.Constant((int)PackageStatus.Shipped);
Expression exprWaiting=Expression.Constant((int)PackageStatus.Waiting);
//左等于右
表达式e1=表达式.Equal(左,exprInProgress);
表达式e2=表达式.Equal(左,exprDelivered);
表达式e3=表达式.Equal(左,exprShipped);
表达式e4=表达式.Equal(左,exprWaiting);
//编写`p.StatusId==(int)PackageStatus.InProgress||
//p.StatusId==(int)PackageStatus.Delivered||
//p.StatusId==(int)PackageStatus.Shipped||
//p.StatusId==(int)PackageStatus.Waiting`
表达式或条件=表达式.OrElse(表达式.OrElse(表达式.OrElse(e1,e2),e3),e4);
//撰写`p=>
//p.StatusId==(int)PackageStatus.InProgress||
//p.StatusId==(int)PackageStatus.Delivered||
//p.StatusId==(int)PackageStatus.Shipped||
//p.StatusId==(int)PackageStatus.Waiting`
返回表达式.Lambda(或条件,新参数表达式[]{p});
}
更新


。请选中@Ankush Answer

尝试此方法,该方法将创建
表达式
作为输入,
bool
作为输出:

public static System.Linq.Expressions.Expression<Func<Package, bool>> IsShippedOrInProgress()
{
    return p => p.StatusId == ( int )PackageStatus.InProgress ||
           p.StatusId == ( int )PackageStatus.Delivered ||
           p.StatusId == ( int )PackageStatus.Shipped ||
           p.StatusId == ( int )PackageStatus.Waiting);
}

是否有更多代码没有显示?是的。其实这只是一个例子。我不能发布真正的代码。我很乐意为您提供所需的一切:-)@TalHumy最好清楚地解释一下您对这些查询的期望是什么?由于明显的原因,自定义方法无法转换为SQL。一种可能的解决方案是使用第三方库,如:“NeinLinq扩展了实体框架等LINQ提供程序,以支持重用函数、重写查询以及使用可翻译谓词和选择器构建动态查询。”您可能需要探索EF如何将C代码翻译成SQL查询。您可以通过使扩展方法返回
Expression
来解决此问题,因此我尝试执行以下操作:db.Users.AsQueryable().Where(u=>u.Id=userResolver.LoggedUserId()&&p.Packages.AsQueryable().Where(IsShippedOrInProgress()),但我收到以下错误:无法解析表达式'u.Package.AsQueryable().Where'(IsShippedOrInProgress(p.OwnerId))“:给定的参数与预期的参数不匹配:无法将类型为”System.Linq.Expressions.MethodCallExpression1“的对象转换为类型为”System.Linq.Expressions.LambdaExpression“。选项更简单+1@TalHumy不确定为什么
IsShippedOrInProgress
方法接收
p.OwnerId
参数。它应该是
Package
type.This
u.Packages.Where(p=>IsShippedOrInProgress())
应该使用实例化方法
IsShippedOrInProgress
@AnkushMadankar创建表达式很简单。问题是如何在另一个表达式树中使用它。如果仔细考虑,您会看到
Where(p=>IsShippedOrInProgress())
不是有效的C#代码。这个问题非常古老-从引入
IQueryable
以来。无法通过表达式树操作来解决。由LINQKit、Neinlq、AutoMapper和其他软件包解决。@TalHumy请查看这篇文章,了解有关在lamba中组合多个表达式的详细信息:嗨,Ramesh,谢谢你r帮助。我希望有一个更简单的解决方案,但是这个worked@TalHumy-Ankush的答案会更简单。用他给出的内容替换方法内容。
private void SomeMethod()
{
    db.Users.AsQueryable()
    .Where(u => u.Id = userResolver.LoggedUserId() &&
         u.Packages.Where(IsShippedOrInProgress())
        .Sum(p => p.Price) > u.MaxCredit)
    .ToList()
}