How to add an AND/OR expression to the following dynamic linq expression

.net c# dynamic-linq expression-trees linq

Question

Let's use the example of the type T, which may or may not contain the property "City". I want to limit the records for the kinds with the attribute "City" such that only people who live in Gotham are returned and sorted.

public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, params object[] values) 
{

    var type = typeof(T);
    var property = type.GetProperty(ordering);
    var parameter = Expression.Parameter(type, "p");
    var propertyAccess = Expression.MakeMemberAccess(parameter, property);
    var orderByExp = Expression.Lambda(propertyAccess, parameter);
    MethodCallExpression resultExp = Expression.Call(
                typeof(Queryable), 
                "OrderBy", 
                new     Type[] { type, property.PropertyType }, 
                source.Expression, 
                Expression.Quote(orderByExp));


    string propertyToRestrictOn = "City";
    string restrictedValue = "Gotham";
    var restrictedProperty = type.GetProperty(propertyToRestrictOn);
    if(null ! = restrictedProperty )
    {
      // TODO: What to add here so than only those records are returned that have a 
      // property named City and the value is 'Gotham'???
    }

   return source.Provider.CreateQuery<T>(resultExp);
}

If you can, provide any relevant literature here as well in case I need to build more complicated searches using And/OR.

The How can I use a string column name in a generic extension method to apply OrderBy to an IQueryable? code was used to create this.

1
0
5/23/2017 11:56:01 AM

Accepted Answer

I believe you are making things more difficult than necessary. The first line of your code (theOrderBy() ), just the lambda included in the query phrase needs to be generated. Additionally, in the optional second portionWhere() ) you can do the same thing essentially by addingExpression.Equal() and Expression.Constant() :

public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering)
{
    var type = typeof(T);
    var property = type.GetProperty(ordering);
    var parameter = Expression.Parameter(type, "p");
    var propertyAccess = Expression.MakeMemberAccess(parameter, property);
    // necessary for value types to work
    var cast = Expression.Convert(propertyAccess, typeof(object));
    var orderByExp = Expression.Lambda<Func<T, object>>(cast, parameter);

    IQueryable<T> result = source.OrderBy(orderByExp);

    string propertyToRestrictOn = "City";
    string restrictedValue = "Gotham";
    var restrictedProperty = type.GetProperty(propertyToRestrictOn);
    if (restrictedProperty != null)
    {
        var restrictionParameter = Expression.Parameter(type, "p");
        var restrictionPropertyAccess =
            Expression.MakeMemberAccess(restrictionParameter, restrictedProperty);
        var restrictionEquality =
            Expression.Equal(restrictionPropertyAccess,
                             Expression.Constant(restrictedValue));
        var whereExp =
            Expression.Lambda<Func<T, bool>>(restrictionEquality, restrictionParameter);

        result = result.Where(whereExp);
    }

   return result;
}

Additionally, I believe you shouldn't label your method "ordering" if it will do other tasks as well.OrderBy() .

1
1/24/2013 7:30:36 PM

Popular Answer

I'm not quite sure if I understand you, but I believe I was in a similar circumstance a few months back. My answer was the here code that was provided.

I believe line 24 should be of particular importance to you.


Edit:

PropertyInfo p = ... // I used reflection in my examply to get properties with a certain Attribute

var expressionParameter = Expression.Parameter(typeof(SomeClass), "lambda");    
var parameter = new [] { expressionParameter };

var propertyAccess = Expression.Property(expressionParameter, p);
var nullCheck = Expression.NotEqual(propertyAccess, Expression.Constant(null, p.PropertyType));
var nullCheckLambda = Expression.Lambda<Func<SomeClass, Boolean>>(nullCheck, parameter);

var containsMethodInfo = typeof(String).GetMethod("Contains", new[] { typeof(String) });
var contains = Expression.Call(propertyAccess, containsMethodInfo, Expression.Constant("ell"));
var containsLambda = Expression.Lambda<Func<SomeClass, Boolean>>(contains, new[] { expressionParameter });

var predicate = Expression.Lambda<Func<SomeClass, Boolean>>(
// line 24 
Expression.AndAlso(nullCheckLambda.Body, containsLambda.Body), parameter);

Console.WriteLine(predicate.ToString());


Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow