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 :)
mógłbyś wyjaśnić, dlaczego nie jest obecny wynik wystarczająco dobre dla? – svick
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
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. –