1

Hi I have a simple query in Entity Framework:

using (var db = new BookstoreContext())
{
    return db.Book
        .Where(w => w.PublishedYear > 2005)
        .ToList();
}

Now I want to change this query to something more dynamic. But I want to change, not only the constant value (2005) but also my column field (PublishedYear).

I am looking for several days how to dynamically build an Expression<Func<,>>. Now i found this page and I'm trying to do so. So far I came to this:

public IEnumerable<Book> GetBooksGreaterThan(string columnName, object value)
{
    using (var db = new BookstoreContext())
    {
        return  db.Book
            .Where(GreaterThan(columnName, value))
            .ToList();
    }
}

public Expression<Func<Book, bool>> GreaterThan(string columnName, object value)
{
    var param = Expression.Parameter(typeof(Book), "w");
    var property = Expression.PropertyOrField(param, columnName);
    var body = Expression.GreaterThan(property, Expression.Constant(value));

    return Expression.Lambda<Func<Book, bool>>(body, param);
}

But in line 15 (var body = Expression.Greater...) a exception is thrown:

The binary operator GreaterThan is not defined for the types 'System.Nullable`1[System.Int32]' and 'System.Int32'.

PS:
My column PublishedYear of the table Book is INT NULL or int? in entity framework class.

The expression w => w.PublishedYear > 2005 so why it keep saying that don't exists this operation? How can I fix it?

Community
  • 1
  • 1
Jonny Piazzi
  • 3,684
  • 4
  • 34
  • 81

2 Answers2

5

The problem is the nullability. You could probably get away with just adding a conversion expression from the value to the type of the property:

public Expression<Func<Book, bool>> GreaterThan(string columnName, object value)
{
    var param = Expression.Parameter(typeof(Book), "w");
    var property = Expression.PropertyOrField(param, columnName);
    var propertyType = typeof(Book).GetProperty(columnName).PropertyType;
    var body = Expression.GreaterThan(property,
         Expression.Convert(Expression.Constant(value), propertyType));

    return Expression.Lambda<Func<Book, bool>>(body, param);
}

This is now effectively doing:

w => w.PublishedYear > (int?) 2005

... which is what the C# code is doing implicitly.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
0

If the value NULL for PublishedYear is permitted but does not actually occur, perhaps you can change the type of argument value in both functions to int? and use value.Value for the comparison in Expression.GreaterThan.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Codor
  • 17,447
  • 9
  • 29
  • 56