2013-07-10 9 views
6

Próbuję utworzyć klasę generyczną, która będzie używana do tworzenia kwerend dla Entity Framework (5).Utwórz drzewo wyrażeń, które generuje parametryczne zapytanie dla obiektu Entity Framework

Mam go do pracy, jedynym problemem jest to, że wartość jest wstrzykiwana jako stała zapytania, a nie jako parametr. Zmniejsza to możliwości, aby EF buforował zapytanie i ponownie używał go później.

Oto, co do tej pory otrzymałem.

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

tej klasy mogą być używane na dwa sposoby:

przez sub-classing go:

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

lub po prostu przez uruchamianiu go:

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

To właśnie udało się osiągnąć do tej pory:

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) 

zamiast

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

Gdybym odkomentowaniu dwa skomentował linie i komentować dwóch wyżej, pojawia się błąd mówiąc, że „wartość” parametr nie jest związany.

Mam nadzieję, że dałem wszystkie użyteczne dane :)

+0

mógłbyś wyjaśnić, dlaczego nie jest obecny wynik wystarczająco dobre dla? – svick

+2

Ponieważ zarówno EF, jak i SQL nie mogą użyć pierwszej kwerendy, aby poprawnie buforować ich dane wyjściowe. Oczywiście EF będzie buforował skompilowane zapytanie, ale ten buforowany element nie będzie użyteczny, dopóki dane wejściowe nie będą dokładnie takie same. To samo dzieje się z SQL Server, który buforuje plan zapytania specyficzny dla tej wartości. – Kralizek

+0

Mam ten sam problem. Wygląda na to, że nie można przekazać Expression.Constant (myValue). Używając [Expression Tree Visualizer] (http://exprtreevisualizer.codeplex.com/) może się okazać, że wartość jest przekazywana jako MemberExpression podczas sprawdzania rzeczywistego działającego zapytania, a nie ConstantExpression, ale nadal nie mogłem pobrać zewnętrznej zmiennej i przekazać go Expression.Property lub podobne. –

Odpowiedz

8

Gdy parametr jest przekazywany jako ConstantExpression, tak:

Expression.Constant(myString) 

... będzie produkować określony, stały symbol na Powstały zapytania:

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

Jeśli używasz innego narzędzia do analizy wyrażenia jak (f => f.Bar == myString)) jak ja z Expression drzewo Visualizer, widzisz th przy parametrze faktycznie jest MemberExpression. Tak więc, jeśli chcesz parametru na swojej wynikającej zapytania, trzeba przejść coś jak nieruchomego obiektu, czy w bardziej dogodnym typu anonimowego:

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

ten sposób jesteś przechodzącą właściwością tylko -created przedmiot i drzewo wyrażenie dostaje MemberExpression, w wyniku następującej CommandText:

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[Bar] AS [Bar], 
FROM [dbo].[Foo] AS [Extent1] 
WHERE [Extent1].[Bar] = @p__linq__0 
+0

Dziękuję :) Spróbuję to jak najszybciej :) – Kralizek

+3

proste i działa, dziękuję – pkmiec

Powiązane problemy