如何使用表达式树创建动态条件
本文关键字:动态 条件 创建 何使用 表达式 | 更新日期: 2023-09-27 18:27:30
请考虑此代码:
System.Linq.Expressions.Expression<Func<tbl, bool>> exp_details = r => r.ID_Master == Id &&
r.Year == Year &&
r.Month == Month ;
我想写一个函数,它需要一些参数,然后从数据库中检索一些数据。问题是我想创建动态条件。例如,如果我传递具有true
值的IsDeleted
参数,我想将r.IsDeleted == true;
添加到exp_details
。我该怎么做?
实现这一点的关键是使用ExpressionVisitor
,它遍历给定的表达式,并且(可选地,在子类中)允许用您指定的其他元素替换已识别的元素。在我的案例中,这是为ORM(NHibernate)所做的。这是我使用的:(我稍后会在回答中添加参考资料)
public class ParameterAssignAndReplacer : ExpressionVisitor
{
private readonly ParameterExpression _source;
private readonly ConstantExpression _target;
internal ParameterAssignAndReplacer(ParameterExpression source, ConstantExpression target)
{
_source = source;
_target = target;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return node.Name == _source.Name ?
base.VisitConstant(_target) :
base.VisitParameter(node);
}
}
而且。。
public static class ExpressionExtensions
{
public static Expression<Func<TArg2, TResult>> AssignAndReduce<TArg1, TArg2, TResult>(
this Expression<Func<TArg1, TArg2, TResult>> func,
TArg1 parameter)
{
var exprBody = func.Body;
var assignedParameter = Expression.Constant(parameter, typeof(TArg1));
exprBody = new ParameterAssignAndReplacer(func.Parameters[0], assignedParameter).Visit(exprBody);
return Expression.Lambda<Func<TArg2, TResult>>(exprBody, func.Parameters[1]);
}
}
这两个类都可以扩展到您的特定场景。为了使其与您发布的代码相关(为了简单起见,我只使用IsDeleted
作为参数):
public class SomeClass
{
Expression<Func<tbl, bool, bool>> _templateExpression =
(tbl r, bool isDeleted) => r.ID_Master == 5 && r.Year == 2008 && r.Month == 12 && r.IsDeleted == isDeleted;
public Expression<Func<tbl, bool>> Foo(bool IsDeleted)
{
return _templateExpression.AssignAndReduce(IsDeleted);
}
}
关于参考文献,我在这个主题上学到的大部分内容都来自Marc Gravell的"表达式"答案[尽管许多其他用户帮助我掌握了这一点:-)]
不能将语句体用于Linq表达式考虑使用谓词代替
var exp_details = new Predicate<tbl>(r =>
{
bool result == Id && r.Year == Year && r.Month == Month;
if(IsDeleted != null)
{
result &= r.IsDeleted == IsDeleted;
}
return result;
});
LinqFunc<T、 bool>表达式可以替换为谓词<T>。
使用"simple"linq表达式生成动态WHERE原因
IQueryable<tbl> query = ent.tbl.Where(r => r.ID_Master == Id && r.Year == Year);
//customize query
if(IsDeleted != null){
query = query.Where(r => r.IsDeleted == IsDeleted);
}
//execute the final generated query
var result = query.FirstOrDefault();
这将从CCD_ 7创建where cause。Linq对于复杂的查询足够聪明。