Search code examples
c#linqentity-frameworklambdaexpression-trees

Dynamic lambda expression (OrderBy) and nullable property type


I'm trying to dynamically create expression that will sort data from database through Entity Framework. But I encountered one problem and cannot overcome it. Maybe let me explain what I'm trying to do. My goal is to create expression like this:

x => x.Property

Where "Property" is the name of property which I'd like to specify dynamically.

Now, let's go to the class, which represents the table in database (I simplified it to make things more clear):

public class MyModelClass
{
    public long MyLongProperty { get; set; }
    public decimal? MyNullableDecimalProperty { get; set; } // IMPORTANT: it's nullable
}

It is my code, where I'm trying to create expression described earlier:

// Db is EntityFramework context
IQueryable<MyModelClass> list = Db.MyModels.Select(x => x);

// x =>
var argument = Expression.Parameter(list.ElementType, "x");

// x.MyNullableDecimalProperty
var propertyToOrder = Expression.Property(argument, "MyNullableDecimalProperty");

// x => x.MyNullableDecimalProperty
var finalExpression = Expression.Call(
    typeof (Queryable),
    "OrderBy",
    new[] { list.ElementType, typeof(IComparable) },
    list.Expression,
    Expression.Lambda<Func<MyModelClass, IComparable>>(propertyToOrder, argument));

list = list.Provider.CreateQuery<MyModelClass>(finalExpression);

Problem occurs at 4th statement (var finalExpression = Expression.Call(...)). I get an exception:

Expression of type „System.Nullable`1[System.Decimal]” cannot be used for return type „System.IComparable”.

As far I understand the problem is with me using "IComparable" type where "MyNullableDecimalProperty" is Nullable and Nullable doesn't user IComparable interface. The exception isn't thrown when I'm ordering by "MyLongProperty" or when I replace "IComparable".

So my questions:

  1. What type should I use to make it work with any nullable properties?

  2. Is it possible to use one type and it will work with all properties whether they are nullable or non-nullable.

Notice: I know I can use for ex. Dynamic Linq library, but I'm not interested in this solution - I'd like to learn how to overcome it without using 3rd party libraries.


Solution

  • There's no reason to use IComparable. Indeed, many types that are comparable do not implement IComparable. Simply use the runtime type of whatever you're passing:

    var finalExpression = Expression.Call(
        typeof (Queryable),
        "OrderBy",
        new[] { list.ElementType, propertyToOrder.Type },
        list.Expression,
        Expression.Lambda(propertyToOrder, new [] { argument }));