0

How can we compare Expression<Func<T, bool>> with T in Entity Framework?

For example:

Expression<Func<Book, bool>> exp = getYellowBooksExpr();
var v = context.Books.Where(exp).ToList();

This above code would run well, but how can we run a query like this:

var v = context.Students.Where(x => x.Book == exp).ToList();
Jacob
  • 3,598
  • 4
  • 35
  • 56
  • Instead of an `Expression>`, don't you want a `Predicate`? – ProgrammingLlama Dec 04 '17 at 15:25
  • 4
    Event if it was possible (it's not), `x.Book == exp` makes no sense when `exp` returns `bool` – Ivan Stoev Dec 04 '17 at 15:26
  • We have a large sets of Expression> we use all over our application and we want to use the same conditions instead of duplicate them for Predicate. – Jacob Dec 04 '17 at 15:27
  • Related: [Entity Framework Filter "Expression>"](https://stackoverflow.com/questions/18337692/entity-framework-filter-expressionfunct-bool) – ProgrammingLlama Dec 04 '17 at 15:30
  • @IvanStoev I mentioned == just for a placeholder for the real expression. Maybe I should have written ?? instead. I saw expressions like: exp.Invoke(x.Book) by using LinqKit but, somhow, it doesn't work for us. – Jacob Dec 04 '17 at 15:31
  • you can make an extension on the `IQueryable`. see [this](https://stackoverflow.com/questions/46895066/using-extension-method-in-linq-to-entities/46896295#46896295) answer – Sam I am says Reinstate Monica Dec 04 '17 at 15:31
  • with x=>exp.Compile().Invoke(x.Book) you can do what you described, but it won't be translatable into SQL (so you'll have to filter in memory after query execution) – DevilSuichiro Dec 04 '17 at 15:34

2 Answers2

1

You cannot do this in general without rewriting your Where expression. But you can use external library, like LinqKit, to do that rewriting for you. Install LinqKit nuget package, then you can do:

var v = context.Students.AsExpandable()
          .Where(x => exp.Invoke(x.Book)).ToList();

This will work for more complex cases too:

var v = context.Students.AsExpandable()
          .Where(x => x.Name == "something" || exp.Invoke(x.Book)).ToList();
Evk
  • 98,527
  • 8
  • 141
  • 191
  • I've tried to prevent using this library but it seems like this is the only way indeed. Thank you – Jacob Dec 04 '17 at 15:59
1

You might use the following

Edited based on the comment below

var students = context.Students.Where(t=>context.Books                               
                     .Where(exp).Contains(t.Book));

Hope this will help you

Monah
  • 6,714
  • 6
  • 22
  • 52
  • 1
    I think just `context.Books.Where(exp).Contains(t.Book)` would work. – juharr Dec 04 '17 at 15:34
  • I edited the answer based on your comment. When I wrote the answer I felt that comparing the object might fail.. hope this hint helps in solving the question – Monah Dec 04 '17 at 15:40
  • EF should translate entity comparisons into SQL that compares the primary key. – juharr Dec 04 '17 at 15:50
  • Running SQL trace, I found it "SQL killer" but it works. Thank you – Jacob Dec 04 '17 at 16:44