c# - 表达式树和 AND 条件

标签 c# filter conditional-statements expression-trees

我正在尝试构建一个过滤器表达式来过滤数据库中的数据。

我编写了以下扩展以根据所选过滤器参数动态构建表达式:

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/

相关文章:

javascript - 在 switch 条件下使用 float 不起作用,为什么?

c# - 在 C# 中显式终止线程

Python Django 返回唯一的保存日期并过滤模型对象

json - 使用 Jackson 进行序列化时如何仅包含特定属性

javascript - Knockout JS过滤

javascript - 是否有适用于 Windows XP 的工具来修复 IE9 问题?

c# - 从 BackgroundWorker 启动时计时器是否工作?

C# 从 array.sum 中排除元素

c# - 使用 SimpleITK for C# 读取 RAW 图像文件

python - Python 中的不等式和括号