合并两个LINQ表达式 [英] Merge two linq expressions
问题描述
我有是在不同的时间建成了两个表达式,但需要为了得到一个准确的where子句中的分组合并。我曾尝试此选项,但我使用实体框架和它doesn'不懂的调用
功能。我见过一些在 ExpressionVisitor
替代的,但我不认为我有什么,我需要做好足够的了解。
如果任何人都可以请点我在正确的方向我将十分感激,那感觉就像是接近那里。
Where子句1A (对象类型表达式来; Func键< T,BOOL>>
)的
{PARM => parm.Name.Contains(帽子)}
Where子句1B 的(对象类型 LambdaExpression
,但可以使用(表达式来; Func键< T,BOOL>>)LambdaExpression
)的
{PARM => parm.Attributes.Any(PARM =>((parm.Name ==测试)AndAlso运算(parm.Value ==21)))}
需要的地方条款
{PARM = GT;
parm.Name.Contains(帽子)(安培;&安培; / ||)
parm.Attributes.Any(PARM =>((parm.Name ==测试)AndAlso运算( parm.Value ==21)))
}
如果有人可以请帮助我合并的 Where子句1A 和 Where子句1B ,我会非常感激。
只是一个供参考在哪里()和任何()子句从IQueryable的,不知道如果该事项获得泛型方法
Func键< MethodInfo的,布尔> methodLambda = M => m.Name ==任何&放大器;&安培; m.GetParameters()==长度2。
MethodInfo的方法= typeof运算(可查询).GetMethods(),其中(methodLambda)。单()MakeGenericMethod(ActualQueryableType)。
ParameterExpression parentMember = Expression.Parameter(typeof运算(T),parentParm);
//创建任何()的表达式树并将其转换为拉姆达
MethodCallExpression callAny = Expression.Call(方法,成员,EXP);
LambdaExpression lambdaAny = Expression.Lambda(callAny,参数);
VAR combExp = parentExp.And((表达式来; Func键< T,BOOL>>)lambdaAny);
MethodCallExpression whereCall = Expression.Call(typeof运算(可查询),去哪儿,新类型[] {} query.ElementType,新的表达式[] {
query.Expression ,
Expression.Quote(combExp)
});
=查询(IQueryable的< T>)query.Provider.CreateQuery(whereCall);
使用,当我得到的错误调用
是
引发NotSupportedException
的LINQ表达式节点类型调用不支持在LINQ到实体。
块引用>
解决方案下面的
的实施PredicateBuilder
不使用调用
:公共静态类PredicateBuilder
{
公共静态表达式来; Func键< T,BOOL>>真< T>(){返回F =>真正; }
公共静态表达式来; Func键< T,BOOL>>假< T>(){返回F =>假; }
公共静态表达式来; Func键< T,BOOL>>或LT; T>(
这个表达式来; Func键< T,BOOL>>表达式1,
表达式来; Func键< T,BOOL>>表达式2)
{
VAR secondBody = expr2.Body.Replace(expr2.Parameters [0],expr1.Parameters [0]);
返回Expression.Lambda<&Func键LT; T,BOOL>>
(Expression.OrElse(expr1.Body,secondBody),expr1.Parameters);
}
公共静态表达式来; Func键< T,BOOL>>和< T>(
这个表达式来; Func键< T,BOOL>>表达式1,
表达式来; Func键< T,BOOL>>表达式2)
{
VAR secondBody = expr2.Body.Replace(expr2.Parameters [0],expr1.Parameters [0]);
返回Expression.Lambda<&Func键LT; T,BOOL>>
(Expression.AndAlso(expr1.Body,secondBody),expr1.Parameters);
}
}
相反,它使用了
替换
办法(下实现),用于替换一个表达式的所有实例与其他。公共静态表达式替换(这个表达式的表情,
表达searchEx,表达replaceEx)
{
返回新ReplaceVisitor(searchEx,replaceEx).Visit(表达);
}
内部类ReplaceVisitor:ExpressionVisitor
{
从,私人只读表达;
公共ReplaceVisitor(从表达,表达于)
{
this.from =距离;
this.to =来;
}
公众覆盖式访问(Expression节点)
{
返回节点==而来?于:base.Visit(节点);
}
}
使用这个,你现在可以使用
和
来,共同两块采取同样的输入谓词表达式。I have two expressions that are built out at separate times, but need to be merged in order to get an accurate 'grouping' of a where clause. I did try this option, but I am using Entity Framework and it doesn't understand the
Invoke
function. I have seen some of theExpressionVisitor
alternative but I do not think I have a good enough understanding of what I need to do.If anyone could please point me in the right direction I would much appreciate it, it feels like it is close to there.
Where Clause 1A (object type
Expression<Func<T, bool>>
){parm => parm.Name.Contains("hat")}
Where Clause 1B (object type
LambdaExpression
, but can use (Expression<Func<T, bool>>)LambdaExpression
){parm => parm.Attributes.Any(parm => ((parm.Name == "test") AndAlso (parm.Value == "21")))}
Needed Where Clause
{parm => parm.Name.Contains("hat") (&&/||) parm.Attributes.Any(parm => ((parm.Name == "test") AndAlso (parm.Value == "21"))) }
If someone could please help me merge Where Clause 1A and Where Clause 1B, I would be very thankful..
Just an FYI Where() and Any() clause are generic methods obtained from IQueryable, not sure if that matters.
Func<MethodInfo, bool> methodLambda = m => m.Name == "Any" && m.GetParameters().Length == 2; MethodInfo method = typeof(Queryable).GetMethods().Where(methodLambda).Single().MakeGenericMethod(ActualQueryableType); ParameterExpression parentMember = Expression.Parameter(typeof(T), "parentParm"); // Create Any() Expression tree and convert it to lambda MethodCallExpression callAny = Expression.Call(method, member, exp); LambdaExpression lambdaAny = Expression.Lambda(callAny, param); var combExp = parentExp.And((Expression<Func<T, bool>>)lambdaAny); MethodCallExpression whereCall = Expression.Call(typeof(Queryable), "Where", new Type[] { query.ElementType }, new Expression[] { query.Expression, Expression.Quote(combExp) }); query = (IQueryable<T>)query.Provider.CreateQuery(whereCall);
The error I get when using
Invoke
is:NotSupportedException
The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.
解决方案Here's an implementation of
PredicateBuilder
that doesn't useInvoke
:public static class PredicateBuilder { public static Expression<Func<T, bool>> True<T>() { return f => true; } public static Expression<Func<T, bool>> False<T>() { return f => false; } public static Expression<Func<T, bool>> Or<T>( this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2) { var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]); return Expression.Lambda<Func<T, bool>> (Expression.OrElse(expr1.Body, secondBody), expr1.Parameters); } public static Expression<Func<T, bool>> And<T>( this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2) { var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]); return Expression.Lambda<Func<T, bool>> (Expression.AndAlso(expr1.Body, secondBody), expr1.Parameters); } }
It instead uses a
Replace
method (implementation below) that replaces all instances of one expression with another.public static Expression Replace(this Expression expression, Expression searchEx, Expression replaceEx) { return new ReplaceVisitor(searchEx, replaceEx).Visit(expression); } internal class ReplaceVisitor : ExpressionVisitor { private readonly Expression from, to; public ReplaceVisitor(Expression from, Expression to) { this.from = from; this.to = to; } public override Expression Visit(Expression node) { return node == from ? to : base.Visit(node); } }
Using this you can now use
And
to AND together two predicate expressions that take the same input.这篇关于合并两个LINQ表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!