作者热门文章
- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试构建一个过滤器表达式来过滤数据库中的数据。
我编写了以下扩展以根据所选过滤器参数动态构建表达式:
public static Expression<Func<T, bool>> And<T>(
this Expression<Func<T, bool>> leftExpression,
Expression<Func<T, bool>> rightExpression)
{
var invocationExpression = Expression.Invoke(rightExpression, leftExpression.Parameters.Cast<Expression>());
var andExpression = Expression.Lambda<Func<T, bool>>(
Expression.AndAlso(leftExpression.Body, invocationExpression),
leftExpression.Parameters);
return andExpression;
}
我是这样使用它的:
Expression<Func<MyObject, bool>> expression = x => true;
if(MyFilter.SomeParam) {
expression = expression.And(x=>x.MyProperty == MyFilter.SomeParam);
}
它适用于 NHibernate,但当我将此代码与 Entity Framework 5 一起使用时,它会失败并显示以下异常消息:
The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.
有一种解决方法是从数据库中获取整个集合,然后通过 IEnumerable.Where(Func<T1, T2> filterClause)
应用过滤条件。 , 但它不需要所有数据就可以在 Expression<Func<T1, T2>>
时获取一条记录表达式直接转换为 SQL 语句。
是否有任何简单的方法可以使此代码与 Entity Framework 一起工作?
最佳答案
尝试来自 Domain Oriented N-Layered .NET 4.0 Sample App 的这个实现(还有 specification pattern 的实现):
public static class ExpressionBuilder
{
public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
{
var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
}
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.And);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.Or);
}
}
public class ParameterRebinder : ExpressionVisitor
{
private readonly Dictionary<ParameterExpression, ParameterExpression> map;
public 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);
}
}
关于c# - 表达式树和 AND 条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15296696/
我是一名优秀的程序员,十分优秀!