构建C#EntityFramework IQueryable表达式

时间:2015-08-20 14:44:18

标签: c# .net expression entity-framework-6 iqueryable

所以我正在尝试构建一个半复杂的搜索表达式,但我一直试图创建一个基本的。用于getValueExpression的表达式如下所示:

x => x.PropertyA != null ? x.PropertyA.ToShortDateString() : "" //nullable datetime
x => x.PropertyB //string property
x => x.PropertyC != null x.PropertyC.ToString() : "" //nullable int

这是我的功能代码,当getValueExpression属于Func类型时,它当前出错,无法与字符串进行比较,这非常有意义,我理解为什么会这样,但我无法弄清楚如何制作获取getValueExpression值以与要搜索的值进行比较的表达式。任何有关正确方向的帮助或领导都将不胜感激。

public static IQueryable<TSource> Search<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, string>> getValueExpression, string searchOption, string searchValue)
{
    var searchValueExpression = Expression.Constant(searchValue);

    var comparisonExpression = Expression.Equal(getValueExpression, searchValueExpression);

    var lambdaExpression = Expression.Lambda<Func<TSource, bool>>(comparisonExpression);

    return source.Where(lambdaExpression);
}

我尝试了类似这样的事情,但遇到了错误的参数数额异常:

var getValueExpressionValue = Expression.Call(getValueExpression.Compile().Method, parameterValueExpression);

2 个答案:

答案 0 :(得分:5)

这是一个让你组成表达式的方法;也就是说你可以使用一个表达式的输出作为另一个表达式的输入,创建一个新表达式,获取第一个表达式的输入和第二个表达式的输出:

public static Expression<Func<TFirstParam, TResult>>
    Compose<TFirstParam, TIntermediate, TResult>(
    this Expression<Func<TFirstParam, TIntermediate>> first,
    Expression<Func<TIntermediate, TResult>> second)
{
    var param = Expression.Parameter(typeof(TFirstParam), "param");

    var newFirst = first.Body.Replace(first.Parameters[0], param);
    var newSecond = second.Body.Replace(second.Parameters[0], newFirst);

    return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}

使用以下方法将一个表达式替换为另一个表达式:

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);
    }
}
public static Expression Replace(this Expression expression,
    Expression searchEx, Expression replaceEx)
{
    return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}

这可以让你写:

public static IQueryable<TSource> Search<TSource>(this IQueryable<TSource> source, 
    Expression<Func<TSource, string>> getValueExpression, 
    string searchOption, 
    string searchValue)
{
    var predicate = getValueExpression.Compose(value => value == searchValue);    
    return source.Where(predicate);
}

答案 1 :(得分:1)

以下是如何做到这一点:

public static IQueryable<TSource> Search<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, string>> getValueExpression, string searchOption, string searchValue)
{
    // const searchValue
    var searchValueExpression = Expression.Constant(searchValue);

    // parameter x
    var parameterExpression = Expression.Parameter(typeof(TSource));

    // func(x)
    var parameterGetValueExpression = Expression.Invoke(getValueExpression, parameterExpression);

    // func(x) == searchValue
    var comparisonExpression = Expression.Equal(parameterGetValueExpression, searchValueExpression);

    // x => func(x) == searchValue
    var lambdaExpression = Expression.Lambda<Func<TSource, bool>>(comparisonExpression, parameterExpression);

    return source.Where(lambdaExpression);
}