Reputation: 4960
I need to share a predicate over 4-5 difference entity sets preferably without duplicating the code. All of the entities implement the interface IEntity
.
private Expression<Func<T, bool>> GetUpdatedPredicate<T>(DateTime? lastUpdated) where T : IEntity {
if (lastUpdated.HasValue) {
return x => (
x.CreatedAt >= lastUpdated ||
(x.UpdatedAt.HasValue && x.UpdatedAt >= lastUpdated)
);
}
return x => true;
}
Then used like this, across multiple entity sets:
(
from s in Db.EntityA.Where(GetUpdatedPredicate<EntityA>(lastUpdated))
where (
s.User.Id == 1
)
select s
).Future();
But gives the error: Unable to cast the type 'EntityA' to type 'IEntity'. LINQ to Entities only supports casting EDM primitive or enumeration types. Is there a way to do this without duplicating the code?
Upvotes: 0
Views: 1112
Reputation: 9294
Entity Framework has issues with your interface type constraint here:
where T : IEntity
You need to add an additional constraint that T needs to be a class:
where T : class, IEntity
Also, if you're starting to discover LINQ expressions, I can highly recommend the LinqKit library. It has some really, really nifty stuff.
Upvotes: 3
Reputation: 22945
EF now tries to include the call to your method into the generated expression, and that will not work. You have to exclude the method-call from the expression.
Try to create the expression from your method before you define your query (no, I haven't tested it).
DateTime lastUpdated = ...;
var updatedPredicate = GetUpdatedPredicate<EntityA>(lastUpdated);
var query =
(
from s in Db.EntityA.Where(updatedPredicate)
where (
s.User.Id == 1
)
select s
).Future();
Upvotes: 0
Reputation: 1079
I am proposing an alternative approach.
Firstly, instead of having a method to return an expression, you will have a private static method like:
private static bool Evaluate(IEntity x, DateTime? lastUpdated) {
if (lastUpdated.HasValue) {
return x.CreatedAt >= lastUpdated ||
(x.UpdatedAt.HasValue && x.UpdatedAt >= lastUpdated)
);
}
return true;
}
Obviously you can name the mention better. Then use it like:
var result = Db.EntityA.Where(i => i.Evaluate(i, lastUpdated));
Upvotes: 0