Filter IQueryable with generic lambda Expression

427 Views Asked by At

I am trying to filter the DateTime? fields of my classes with a generic function. But I got the error "The LINQ expression could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync()."

And I dont know what is wrong.

This is my extension function:

public static IQueryable<TEntity>? FilterDateField<TEntity>(this IQueryable<TEntity> entities, Expression<Func<TEntity, DateTime?>> dbField, DateTime dateField)
{
    var t1 = entities.Where(e=>dbField.Compile().Invoke(e).HasValue && dbField.Compile().Invoke(e)== dateField);

    return t1;
}
1

There are 1 best solutions below

0
On BEST ANSWER

I get the answer from another question here: Generic Linq to Entities filter method that accepts filter criteria and properties to be filtered

It was just add this code in the class who holds the FilterDateField function

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

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

And them use de Compose like this:

public static IQueryable<TEntity>? FilterDateField<TEntity>(this IQueryable<TEntity> entities, Expression<Func<TEntity, DateTime?>> dbField, DateTime dateField)
{
    var dateHasValue = dbField.Compose(value => value.HasValue);
    var t1 = entities.Where(dateHasValue);

    return t1;
}