Trouble with building a C# EntityFramework IQueryable Expression

▼魔方 西西 提交于 2020-01-09 11:45:21

问题


So I'm attempting to build a semi complication Search expression, but I'm stuck trying to create a basic one. The expressions being used for getValueExpression look something like:

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

Here is my function code, it currently errors when getValueExpression being of type Func that can't be compared to a string, which makes perfect sense and I understand why that is, but I'm having trouble figuring out how to make an expression that gets the value of getValueExpression to compare to the value being searched for. Any help or leads in the right direction would be greatly appreciated.

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);
}

I've attempted similar things like this, but have met failure with incorrect arguments amount exception:

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

回答1:


Here is a method that will let you compose expressions; that is to say you can use the output of one expression as the input of another, creating a new expression taking the input that the first takes and the output that the second takes:

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);
}

Which uses the following method to replace one expression with another:

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);
}

This lets you write:

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);
}



回答2:


Here is how you can do it :

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);
}


来源:https://stackoverflow.com/questions/32121353/trouble-with-building-a-c-sharp-entityframework-iqueryable-expression

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!