C# 表达式树与条件

C# 表达式树与条件,c#,filter,conditional-statements,expression-trees,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

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

我编写了以下扩展,以根据选定的筛选器参数动态构建表达式:

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;
}
公共静态表达式和(
这个表达式是左表达式,,
表达式(右表达式)
{
var invocationExpression=Expression.Invoke(rightExpression,leftExpression.Parameters.Cast());
var andExpression=Expression.Lambda(
Expression.AndAlso(leftExpression.Body,invocationExpression),
leftExpression.Parameters);
返回和表达;
}
我是这样使用它的:

Expression<Func<MyObject, bool>> expression = x => true;

if(MyFilter.SomeParam) {
    expression = expression.And(x=>x.MyProperty == MyFilter.SomeParam);
}
Expression=x=>true;
if(MyFilter.SomeParam){
expression=expression.And(x=>x.MyProperty==MyFilter.SomeParam);
}
它与NHibernate配合使用非常好,但当我将此代码与Entity Framework 5配合使用时,它会失败,并显示以下异常消息:

LINQ to实体中不支持LINQ表达式节点类型“Invoke”

有一种解决方法可以从数据库中获取整个集合,然后通过
IEnumerable.Where(Func filterClause)
应用过滤条件,但它不需要所有数据就可以获得一条记录,而
表达式
表达式直接转换为SQL语句


有什么简单的方法可以让代码与实体框架一起工作吗?

如果你总是想“和”你的谓词,你不需要弄乱表达式树,只需要为每个谓词添加额外的where子句。请参阅。

请在下面的博文中找到解决方案:

这篇博文的作者提供了另一个实现“Add”方法来组合2个表达式

/// <summary>
/// Enables the efficient, dynamic composition of query predicates.
/// </summary>
public static class PredicateBuilder
{
    /// <summary>
    /// Creates a predicate that evaluates to true.
    /// </summary>
    public static Expression<Func<T, bool>> True<T>() { return param => true; }

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

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

    /// <summary>
    /// Combines the first predicate with the second using the logical "and".
    /// </summary>
    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);
    }

    /// <summary>
    /// Combines the first predicate with the second using the logical "or".
    /// </summary>
    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);
    }

    /// <summary>
    /// Negates the predicate.
    /// </summary>
    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);
    }

    /// <summary>
    /// Combines the first expression with the second using the specified merge function.
    /// </summary>
    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);
        }
    }
}
//
///支持查询谓词的高效、动态组合。
/// 
公共静态类谓词生成器
{
/// 
///创建一个计算结果为true的谓词。
/// 
公共静态表达式True(){return param=>True;}
/// 
///创建计算结果为false的谓词。
/// 
公共静态表达式False(){return param=>False;}
/// 
///从指定的lambda表达式创建谓词表达式。
/// 
公共静态表达式创建(表达式谓词){返回谓词;}
/// 
///使用逻辑“and”组合第一个谓词和第二个谓词。
/// 
公共静态表达式和(第一个表达式,第二个表达式)
{
首先返回.Compose(第二个是Expression.AndAlso);
}
/// 
///使用逻辑“or”组合第一个谓词和第二个谓词。
/// 
公共静态表达式或(第一个表达式,第二个表达式)
{
首先返回.Compose(第二个是Expression.OrElse);
}
/// 
///否定谓词。
/// 
公共静态表达式不是(此表达式)
{
var negated=Expression.Not(Expression.Body);
返回表达式.Lambda(否定,表达式.Parameters);
}
/// 
///使用指定的合并函数将第一个表达式与第二个表达式合并。
/// 
静态表达式组合(先此表达式,后表达式,Func merge)
{
//zip参数(从第二个参数映射到第一个参数)
var map=first.Parameters
.Select((f,i)=>new{f,s=second.Parameters[i]})
.ToDictionary(p=>p.s,p=>p.f);
//用第一个lambda表达式中的参数替换第二个lambda表达式中的参数
var secondBody=ParameterRebinder.ReplaceParameters(映射,second.Body);
//使用第一个表达式中的参数创建合并的lambda表达式
返回表达式.Lambda(merge(first.Body,secondBody),first.Parameters);
}
类参数reBinder:ExpressionVisitor
{
只读字典地图;
ParameterRebinder(字典映射)
{
this.map=map??新建字典();
}
公共静态表达式替换参数(字典映射、表达式表达式)
{
返回新参数浏览器(map)。访问(exp);
}
受保护的重写表达式VisitParameter(ParameterExpression p)
{
参数表达替换;
if(映射TryGetValue(p,输出替换))
{
p=替换;
}
返回基访问参数(p);
}
}
}

从尝试此实现(还有以下实现):

公共静态类ExpressionBuilder
{
公共静态表达式组合(此表达式优先,表达式第二,Func合并)
{
var map=first.Parameters.Select((f,i)=>new{f,s=second.Parameters[i]})。ToDictionary(p=>p.s,p=>p.f);
var secondBody=ParameterRebinder.ReplaceParameters(映射,second.Body);
返回表达式.Lambda(merge(first.Body,secondBody),first.Parameters);
}
公共静态表达式和(第一个表达式,第二个表达式)
{
首先返回。编写(第二,表达式。和);
}
公共静态表达式或(第一个表达式,第二个表达式)
{
首先返回.Compose(第二个,表达式.Or);
}
}
公共类参数Rebinder:ExpressionVisitor
{
私有只读字典映射;
公共参数索引(字典映射)
{
this.map=map??新建字典();
}
公共静态表达式替换参数(字典映射、表达式表达式)
{
返回新参数浏览器(map)。访问(exp);
}
受保护的重写表达式VisitParameter(ParameterExpression p)
{
参数表达替换;
if(映射TryGetValue(p,输出替换))
{
p=替换;
}
返回基访问参数(p);
}
}
“仅链接”的答案在这里往往不受欢迎。你能不能至少提供一份摘要或ot
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);
    }

}