Create an Expression Tree that generates a parametric query for Entity Framework

entity-framework expression-trees

Question

I'm attempting to develop a generic class for Entity Framework queries (5).

I managed to get it work, however the value is injected into the query as a constant rather than a parameter, which is the only issue. As a result, there are less chances that EF will store the query and utilize it again in the future.

What I have thus far is this.

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);
    }
}

there are two methods to utilize this class:

Subclassifying it:

public class MinCreationDateCandidateFilter : MinDateFilter<Candidate>
{
    public MinCreationDateCandidateFilter(DateTime @from) : base(c => c.CreationDate, @from) {}
}

either by instantiating it directly:

var filter = new MinDateFilter<Entities.Transition>(t => t.Date, from.Value);

This is what I have so far been able to accomplish:

SELECT 
[Extent1].[Id] AS [Id]
-- Other fields
FROM [dbo].[Candidates] AS [Extent1]
WHERE [Extent1].[CreationDate] > convert(datetime2, '1982-12-09 23:59:59.9990000', 121)

in place of

SELECT 
[Extent1].[Id] AS [Id]
-- Other fields
FROM [dbo].[Candidates] AS [Extent1]
WHERE [Extent1].[CreationDate] > @p__linq__0

I get an error stating that the parameter "value" isn't constrained if I uncomment the two lines that have already been commented and comment the two above.

I think I covered all the important information.

1
6
7/10/2013 11:31:38 AM

Accepted Answer

A parameter that is supplied as aConstantExpression such like this:

Expression.Constant(myString)

On the resultant expression, it will output a fixed, constant symbol.

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[Bar] AS [Bar], 
FROM [dbo].[Foo] AS [Extent1]
WHERE [Extent1].[Bar] = "Some text"

If you use a tool to evaluate a phrase like(f => f.Bar == myString)) You can see that the parameter is really a, as I demonstrated using Expression Tree Visualizer.MemberExpression . In order to supply a parameter to the resultant query, you must either pass an object property or the more practical anonymous type:

Expression.Property(
    Expression.Constant(new { Value = myString }),
    "Value"
)

In this manner, a property of the just generated object is passed and your expression tree receives aMemberExpression , which led to the followingCommandText :

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[Bar] AS [Bar], 
FROM [dbo].[Foo] AS [Extent1]
WHERE [Extent1].[Bar] = @p__linq__0
11
2/7/2014 7:52:50 PM


Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow