Ich versuche, eine generische Klasse zum Erstellen von Abfragen für Entity Framework (5) zu erstellen.Erstellen Sie eine Ausdrucksbaumstruktur, die eine parametrische Abfrage für Entity Framework generiert
Ich habe es funktioniert, das einzige Problem ist, dass der Wert als eine Konstante der Abfrage statt als ein Parameter injiziert wird. Dies reduziert die Möglichkeiten für EF, die Abfrage zwischenzuspeichern und später wiederzuverwenden.
Das ist, was ich bis jetzt bekommen habe.
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);
}
}
diese Klasse kann auf zwei Arten verwendet werden:
von Sub-Klassierung es:
public class MinCreationDateCandidateFilter : MinDateFilter<Candidate>
{
public MinCreationDateCandidateFilter(DateTime @from) : base(c => c.CreationDate, @from) {}
}
oder einfach durch Instanziieren:
var filter = new MinDateFilter<Entities.Transition>(t => t.Date, from.Value);
Dies ist, was ich geschafft, bis jetzt zu erreichen:
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)
statt
SELECT
[Extent1].[Id] AS [Id]
-- Other fields
FROM [dbo].[Candidates] AS [Extent1]
WHERE [Extent1].[CreationDate] > @p__linq__0
Wenn ich Kommentar- der zwei Zeilen kommentiert und ich kommentieren Sie die beiden oben, erhalte ich eine Fehlermeldung, dass der Parameter „Wert“ ist nicht gebunden.
Ich hoffe, ich habe all nützlichen Details :)
Können Sie sich erklären, warum ist nicht das aktuelle Ergebnis gut genug für Sie? – svick
Da EF und SQL die erste Abfrage nicht verwenden können, um ihre Ausgabe ordnungsgemäß zwischenzuspeichern. Natürlich wird EF die kompilierte Abfrage zwischenspeichern, aber das zwischengespeicherte Element wird nicht verwendbar sein, wenn die Eingabe nicht genau gleich ist. Gleiches passiert mit SQL Server, der den für diesen Wert spezifischen Abfrageplan zwischenspeichert. – Kralizek
Ich habe das gleiche Problem. Es scheint, dass Sie Expression.Constant (myValue) nicht übergeben können. Wenn Sie [Expression Tree Visualizer] (http://exprtreevisualizer.codeplex.com/) verwenden, werden Sie möglicherweise feststellen, dass der Wert als MemberExpression übergeben wird, wenn eine tatsächlich aktive Abfrage geprüft wird, nicht ConstantExpression, aber ich konnte immer noch keine externe Variable abrufen und übergeben Sie es mit Expression.Property oder ähnlich. –