Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.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
Linq EF Core,在任何条件下追加到谓词生成器_Linq_Entity Framework Core_Predicatebuilder - Fatal编程技术网

Linq EF Core,在任何条件下追加到谓词生成器

Linq EF Core,在任何条件下追加到谓词生成器,linq,entity-framework-core,predicatebuilder,Linq,Entity Framework Core,Predicatebuilder,我试图在下面代码的任意子句中合并两个谓词,但我找不到一种方法 private static Expression<Func<Order, bool>> BuildWhereExpression(DataFilterOrder filter, AppDbContext dbContext) { var predicate = PredicateBuilder.True<Order>(); var confirmationPredicate = Predica

我试图在下面代码的任意子句中合并两个谓词,但我找不到一种方法

private static Expression<Func<Order, bool>> BuildWhereExpression(DataFilterOrder filter, AppDbContext dbContext)
{

var predicate = PredicateBuilder.True<Order>();

var confirmationPredicate = PredicateBuilder.True<HConfirmation>();

if (!string.IsNullOrWhiteSpace(filter.ConfirmationNumber))
{
  confirmationPredicate = confirmationPredicate.And(r =>
  r.Confirmation.Document.Number == filter.ConfirmationNumber);
}
if (filter.ConfirmationDateFrom != null)
{
  confirmationPredicate = confirmationPredicate.And(r =>
  r.Confirmation.Document.Date >= filter.ConfirmationDateFrom);
}
.....


predicate = predicate.And(o =>
   dbContext.Confirmations
   .Join(
     dbContext.DocumentHierarchies,
     c => c.DocumentId,
     h => h.ChildDocumentId,
     (c, h) => new HConfirmation { Confirmation = c, Hierarchy = h })
   .Any(r => r.Hierarchy.ParentDocumentId == o.DocumentId && 
   ???confirmationPredicate???)

  return predicate;
}
....

// called by

  var wherePredicate = BuildWhereExpression(filter, dbContext);


  var list = await dbContext.Orders
    .Where(wherePredicate)
    .ToListAsync();


嗯,试图简化解决方案,但似乎需要动态构建
任何
零件。对不起,没有测试,这里可能有一些小错误

私有静态表达式BuildWhereExpression(DataFilterOrder筛选器,AppDbContext dbContext)
{
var predicate=PredicateBuilder.True();
var-confirmationPredicate=PredicateBuilder.True();
如果(!string.IsNullOrWhiteSpace(filter.ConfirmationNumber))
{
确认谓词=确认谓词。和(r=>
r、 Confirmation.Document.Number==filter.ConfirmationNumber);
}
if(filter.ConfirmationDateFrom!=null)
{
确认谓词=确认谓词。和(r=>
r、 Confirmation.Document.Date>=filter.ConfirmationDateFrom);
}
.....
//我们可以单独编写这个查询
var confirmations=dbContext.confirmations
.Join(dbContext.documentHierarchys,
c=>c.DocumentId,
h=>h.ChildDocumentId,
(c,h)=>新的HConfirmation{Confirmation=c,Hierarchy=h}
);
var orderParam=表达式参数(typeof(Order),“o”);
var hconfimationparam=表达式参数(typeof(hconfimation),“r”);
//r.Hierarchy.ParentDocumentId==o.DocumentId
var anyPredicate=(Expression)Expression.Equal(Expression.Property)(Expression.Property(hconfimationparam,“Hierarchy”),“ParentDocumentId”),
Expression.Property(orderParam,“DocumentId”);
//r.确认
var confirmationAccess=Expression.Property(hConfirmationParam,“Confirmation”);
//纠正确认谓词
var confirmationPredicateCorrected=ExpressionReplacer.GetBody(confirmationPredicate,confirmationAccess);
//r.Hierarchy.ParentDocumentId==o.DocumentId&&confirmationPredicateCorrected
anyPredicate=Expression.AndAlso(anyPredicate,confirmationPredicateCorrected);
//r=>r.Hierarchy.ParentDocumentId==o.DocumentId&&confirmationPredicateCorrected
var anyLambda=Expression.Lambda(anyPredicate,hconfimationparam);
var anyCall=Expression.Call(typeof(Queryable),“Any”,new[]{typeof(hconfimation)},confirmations.Expression,Expression.Quote(anyLambda));
var additionalPredicate=Expression.Lambda(anyCall,orderParam);
谓词=谓词和(附加谓词);
返回谓词;
}
无论如何,需要额外的助手类:

公共类ExpressionReplacer:ExpressionVisitor
{
只读IDictionary _replaceMap;
public ExpressionReplacer(IDictionary replaceMap)
{
_replaceMap=replaceMap??抛出新的ArgumentNullException(nameof(replaceMap));
}
公共重写表达式访问(表达式扩展)
{
if(exp!=null&&u replaceMap.TryGetValue(exp,out var replacement))
退换货;
返回基地访问(exp);
}
公共静态表达式替换(表达式expr、表达式toReplace、表达式toExpr)
{
返回新的ExpressionReplacer(新字典{{toReplace,toExpr}});
}
公共静态表达式替换(表达式表达式表达式、IDictionary替换映射)
{
返回新的ExpressionReplacer(replaceMap)。访问(expr);
}
公共静态表达式GetBody(LambdaExpression lambda,params Expression[]toReplace)
{
if(lambda.Parameters.Count!=toReplace.Length)
抛出新的InvalidOperationException();
返回新的ExpressionReplacer(Enumerable.Range(0,lambda.Parameters.Count)
.ToDictionary(i=>(表达式)lambda.Parameters[i],i=>toReplace[i]).Visit(lambda.Body);
}
}

强烈建议将此扩展用于表达式树可视化和调试:

Any(confirmationPredicate.and(r=>r.Hierarchy.ParentDocumentId==o.DocumentId))
@IvanStoev引发异常:System.InvalidCastException:无法将类型为“System.Linq.Expressions.InstanceMethodCallExpression1”的对象强制转换为类型为“System.Linq.Expressions.LambdaExpression”。堆栈跟踪:ExpressionExtensions.UnwaplambFromQuote(表达式表达式)不太容易,但可行。哪个是调用方法(dbContext等)的签名?@SvyatoslavDanyliv已更新。
public static class PredicateBuilder
    {

        // Creates a predicate that evaluates to true.        
        public static Expression<Func<T, bool>> True<T>() { return param => true; }

        // Creates a predicate that evaluates to false.        
        public static Expression<Func<T, bool>> False<T>() { return param => false; }

        // Creates a predicate expression from the specified lambda expression.        
        public static Expression<Func<T, bool>> Create<T>(Expression<Func<T, bool>> predicate) { return predicate; }
        public static Expression<Func<T, bool>> Create1<T, K>(Expression<Func<T, bool>> predicate, K obj) { return predicate; }

        // Combines the first predicate with the second using the logical "and".        
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.AndAlso);
        }

        // Combines the first predicate with the second using the logical "or".        
        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.OrElse);
        }

        // Negates the predicate.        
        public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expression)
        {
            var negated = Expression.Not(expression.Body);
            return Expression.Lambda<Func<T, bool>>(negated, expression.Parameters);
        }

        // Combines the first expression with the second using the specified merge function.        
        static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
        {
            // zip parameters (map from parameters of second to parameters of first)
            var map = first.Parameters
                .Select((f, i) => new { f, s = second.Parameters[i] })
                .ToDictionary(p => p.s, p => p.f);

            // replace parameters in the second lambda expression with the parameters in the first
            var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);

            // create a merged lambda expression with parameters from the first expression
            return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
        }

        class ParameterRebinder : ExpressionVisitor
        {
            readonly Dictionary<ParameterExpression, ParameterExpression> map;

            ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
            {
                this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
            }

            public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
            {
                return new ParameterRebinder(map).Visit(exp);
            }

            protected override Expression VisitParameter(ParameterExpression p)
            {
                ParameterExpression replacement;
                if (map.TryGetValue(p, out replacement))
                {
                    p = replacement;
                }
                return base.VisitParameter(p);
            }
        }
    }