I have read about 30 Stack Overflow questions, and about 20 blogs and cannot find my answer. That said, I am sure the answer I require is out there so if you know of it please point it out (please note the last paragraph/sentence about answers that do not fit my requirement). Thanks!
I am persisting instances of classes that have a similar shape to:
public class Data {
public int Id { get; set; }
}
public class Container {
public int Id { get; set; }
public Data Data { get; set; }
}
Currently queries are written to find Containers via an abstraction layer that requires a Lambda Expression accepting a Container and returning bool (predicate). It will not accept IQueryable even though Entity Framework 5 is the ORM of choice.
My task is to present an API surface based around Lambda Expressions that accept the Data type. I cannot change the abstraction layer (I must pass a predicate that accepts a Container) so I am trying to convert an expression I receive as:
Expression<Func<Data , bool>>
to:
Expression<Func<Container , bool>>
I have added an extra method in my repository class like these:
public Container Find( Expression<Func<Data , bool>> predicate ) {
IEnumerable<Container> result = QueryStrategy.Fetch( c => predicate.Compile().Invoke( c.Data ) );
return result.FirstOrDefault();
}
This compliments the existing Find method:
public Container Find( Expression<Func<Container , bool>> predicate ) {
IEnumerable<Container> result = QueryStrategy.Fetch( predicate );
return result.FirstOrDefault();
}
When the former method is used it produces the following exception:
LINQ to Entities does not recognize the method ‘Boolean
Invoke(Container.Data)’ method, and this method cannot be
translated into a store expression.
I have tried all sorts of things with Expression classes I just can’t see a way to map:
Expression<Func<Data , bool>>
to:
Expression<Func<Container , bool>>
Without using Invoke which is not supported by Entity Framework (but works fine with in memory enumerable data).
Can anybody help me get the above scenario working using Expressions?
I understand that I may be able to use the LinqKit library to solve this, but I really want to solve this problem without bringing in a third party library.
UPDATE: In my effort to present a simplified problem, I have implied (by originally using DbContext in the code sample) that the code would have access to IQueryable and/or be suitable for using LinqKit’s AsExpandable(). In reality this is not the case – the repository class is not allowed to use IQueryable or any vendor specific extensions. I have modified the examples above and hopefully this makes things clearer.
This Issue Is Now Solved
I have managed to solve the problem after 4 hours of reading/tinkering with Expressions (amazing technology).
I have put this class together (it is not polished or final but shows how it was achieved):
And it can be used like this:
In theory one should be able to traverse deeper relationships by examining propertyNameExpression but I have had enough for today.
I can now see that the SQL Entity Framework has generated for each flavour of query is identical:
========================
========================
========================