I am trying to create a generic class that will be used to compile queries for Entity Framework (5).
I got it to work, the only problem is that the value is entered as a query constant, not as a parameter. This reduces the ability of EF to cache the request and reuse it later.
This is what I got so far.
public class MinDateFilter<T> : IFilter<T> where T : class { private readonly Expression<Func<T, bool>> _predicate; public MinDateCandidateFilter(Expression<Func<T, DateTime>> propertySelector, DateTime from) { from = from.Date.AddDays(-1); from = new DateTime(from.Year, from.Month, from.Day, 23, 59, 59, 999); Expression value = Expression.Constant(from, typeof(DateTime)); //ParameterExpression variable = Expression.Variable(typeof(DateTime), "value"); MemberExpression memberExpression = (MemberExpression)propertySelector.Body; ParameterExpression parameter = Expression.Parameter(typeof(T), "item"); Expression exp = Expression.MakeMemberAccess(parameter, memberExpression.Member); Expression operation = Expression.GreaterThan(exp, value); //Expression operation = Expression.GreaterThan(exp, variable); _predicate = Expression.Lambda<Func<T, bool>>(operation, parameter); } public IQueryable<T> Filter(IQueryable<T> items) { return items.Where(_predicate); } }
This class can be used in two ways:
by subclassification:
public class MinCreationDateCandidateFilter : MinDateFilter<Candidate> { public MinCreationDateCandidateFilter(DateTime @from) : base(c => c.CreationDate, @from) {} }
or simply by creating it:
var filter = new MinDateFilter<Entities.Transition>(t => t.Date, from.Value);
This is what I have managed to achieve so far:
SELECT [Extent1].[Id] AS [Id]
instead
SELECT [Extent1].[Id] AS [Id] -- Other fields FROM [dbo].[Candidates] AS [Extent1] WHERE [Extent1].[CreationDate] > @p__linq__0
If I uncomment the two commented lines, and I comment the two above, I get an error message indicating that the value parameter is not connected.
Hope I gave all the useful details :)