Wykonaj GetCurrentFilter
a (tylko do odczytu) zamiast metody. EF będzie porównywać właściwości z ich wartościami, zamiast próbować tłumaczyć je na SQL, w przeciwieństwie do metod.
Jedyna inna droga, że trzeba to przemierzać całą drzewa wyrażenie, szukaj wykorzystania metodę ResultOf
, oceny jego parametrów do wartości, a następnie wbudować tę wartość na którym połączenie ResultOf
kiedyś, rebuiding zapytanie wokół tej wartości.
Aby to zadziałało, oznacza to, że musisz nie tylko zawijać kod, który chcesz umieścić w linii, w rozmowie z numerem EfUtil.ResultOf
, ale także wywoływać metodę w samym zapytaniu, aby wymusić jej powrót i jej ocenę. :
public class EfUtil
{
public static T ResultOf<T>(T value)
{
return value;
}
}
//Note this could probably use a better name
public static IQueryable<T> EvaluateResults<T>(this IQueryable<T> query)
{
return query.Provider.CreateQuery<T>(
new ExpressionEvaluator().Visit(query.Expression));
}
internal class ExpressionEvaluator : ExpressionVisitor
{
protected override Expression VisitMethodCall(MethodCallExpression m)
{
if (m.Method.Name == "ResultOf" && m.Method.DeclaringType == typeof(EfUtil))
{
Expression target = m.Arguments[0];
object result = Expression.Lambda(target)
.Compile()
.DynamicInvoke();
return Expression.Constant(result, target.Type);
}
else
return base.VisitMethodCall(m);
}
}
pozwoliłoby to napisać:
var result = context.EntitySet.Where(x=> x.column > EfUtil.ResultOf(GetCurrentFilter(state)))
.EvaluateResults();
byłoby wtedy ocenić GetCurrentFilter(state)
po stronie klienta i inline wynik jako stała w zapytaniu.
W nieco prostszym testu, możemy napisać następujący:
var query = new[] { 1, 2, 3 }
.AsQueryable()
.Where(x => x > EfUtil.ResultOf(Math.Max(1, 2)))
.EvaluateResults();
Console.WriteLine(query.ToString());
I to wydrukować.
System.Int32 [] Gdzie (x => (x> 2))
Dokładnie tego chcemy.
Należy pamiętać, że użycie parametru lambda (x
w tych przykładach) nie może być używane w dowolnym miejscu połączenia pod numerem EfUtil.ResultOf
, ponieważ kod nie będzie działał i nie będzie mógł zostać uruchomiony (chociaż możemy wygenerować lepszy komunikat o błędzie, jeśli dbamy o to wystarczająco).
Ta metoda może mieć kilka parametrów, z których żadne nie są używane w zapytaniu. Nie ma możliwości zdefiniowania sparametryzowanych właściwości w języku C#. Ale masz rację, ponieważ nie wyjaśniłem tego w moim pytaniu. Pozwól mi to zaktualizować. –
@ zespri Ten problem jest rozwiązywalny, chociaż ma dodatkowe ograniczenie. – Servy
Kompilowanie lambda dla każdego wydanego zapytania spowoduje duże obciążenie procesora. Ile czasu zajmuje kompilacja lambda? 1ms? – usr