Search code examples
c#.net.net-corereflectionexpression-trees

Dynamically building an expression tree for an EF Where() clause


I want to build a custom Where expression that I can pass to the Where clause of an Entity Framework query.

Below is as far as I've got.

// ???

ParameterExpression pe = Expression.Parameter(typeof(StorageDetail), "d");

if (HasRailcarNumber.HasValue)
{
    Expression left = Expression.Property(pe, typeof(StorageDetail).GetProperty("RailcarNumber"));
    Expression right = Expression.Constant(null);
    Expression e2 = (HasRailcarNumber.Value == true) ?
        Expression.Equal(left, right) :
        Expression.NotEqual(left, right);

    // What to do with e2 ???

}

if (IsTakeOrPay.HasValue)
{
    Expression left = Expression.Property(pe, typeof(StorageDetail).GetProperty("TakeOrPayStartDate"));
    Expression right = Expression.Constant(null);
    Expression e2 = (HasRailcarNumber.Value == true) ?
        Expression.Equal(left, right) :
        Expression.NotEqual(left, right);

    // What to do with e2 ???

}

if (HasArrived.HasValue)
{
    Expression left = Expression.Property(pe, typeof(StorageDetail).GetProperty("ArrivalDate"));
    Expression right = Expression.Constant(null);
    Expression e2 = (HasRailcarNumber.Value == true) ?
        Expression.Equal(left, right) :
        Expression.NotEqual(left, right);

    // What to do with e2 ???

}

My first question is how do I start the body? I don't want my expresion to call Where(). I want Where to call my expression.

Second question is once I have my subexpressions (e2 above), how do I combine them? (Using AndAlso.) Note that it's possible that all three properties are null, in which case the expression should not filter anything (should be a null expression).


Solution

  • As you've assumed you should use Expression.AndAlso for AND logic. If it is the case, you can create "start" expression evaluating to true and add others to it:

    Expression expr = Expression.Constant(true);
    if (HasRailcarNumber.HasValue)
    {
        ...
        expr = Expression.AndAlso(expr, e2);
    }
    if (IsTakeOrPay.HasValue)
    {
        ...
        expr = Expression.AndAlso(expr, e2);
    }
    if (HasArrived.HasValue)
    {
        ...
        expr = Expression.AndAlso(expr, e2);
    }