Jestem w trakcie pisania warstwy danych dla części naszego systemu, która rejestruje informacje o automatycznych zleceniach uruchamianych każdego dnia - nazwa zlecenia , jak długo działał, jaki był wynik, itp.Używanie LINQ ExpressionVisitor do zamiany parametrów pierwotnych na odwołania do właściwości w wyrażeniu lambda
Mówię do bazy danych za pomocą Entity Framework, ale staram się ukryć te szczegóły z modułów wyższego poziomu i nie chcę obiekty obiektów same się ujawniają.
Jednak chciałbym, aby mój interfejs był bardzo elastyczny w kryteriach, które wykorzystuje do wyszukiwania informacji o zadaniach. Na przykład interfejs użytkownika powinien umożliwiać użytkownikowi wykonywanie złożonych zapytań, takich jak "daj mi wszystkie zadania o nazwie" cześć ", które trwały między godziną 10:00 a 11:00, co nie powiodło się." Oczywiście wygląda to jak zadanie dla dynamicznie budowanych drzewek Expression
.
Więc co chciałbym moje warstwy danych (repozytorium), aby być w stanie zrobić, to zaakceptować LINQ wyrażeń typu Expression<Func<string, DateTime, ResultCode, long, bool>>
(wyrażenie lambda), a następnie za kulisami przekonwertować do wyrażenia lambda, że moja Entity Framework ObjectContext
mogą korzystać jako filtr wewnątrz klauzuli Where()
.
W skrócie, próbuję przekonwertować wyrażenia lambda typu Expression<Func<string, DateTime, ResultCode, long, bool>>
do Expression<Func<svc_JobAudit, bool>>
, gdzie svc_JobAudit
obiektem danych Entity Framework, która odpowiada tabeli, gdzie informacje są przechowywane zadanie. (Cztery parametry pierwszego uczestnika odpowiadają nazwie zadania, wynikowi, i ile czasu zajęło mu odpowiednio MS)
Robiłem bardzo duże postępy, używając klasy ExpressionVisitor
, dopóki nie trafiłem mur z cegły i otrzymał InvalidOperationException
z tym komunikatem o błędzie:
Wywołany z „VisitLambda”, przepisywanie węzeł typu „System.Linq.Expressions.ParameterExpression” musi wrócić niezerowym wartość Instrumentu taki sam typ. Możesz też zastąpić "VisitLambda" i , aby nie odwiedzać dzieci tego typu.
Jestem kompletnie zaskoczony. Dlaczego do cholery nie pozwala mi konwertować węzłów wyrażeń, które odwołują się do parametrów do węzłów, które odwołują się do właściwości? Czy istnieje inny sposób, aby o tym poradzić?
Oto przykładowy kod:
namespace ExpressionTest
{
class Program
{
static void Main(string[] args)
{
Expression<Func<string, DateTime, ResultCode, long, bool>> expression = (myString, myDateTime, myResultCode, myTimeSpan) => myResultCode == ResultCode.Failed && myString == "hello";
var result = ConvertExpression(expression);
}
private static Expression<Func<svc_JobAudit, bool>> ConvertExpression(Expression<Func<string, DateTime, ResultCode, long, bool>> expression)
{
var newExpression = Expression.Lambda<Func<svc_JobAudit, bool>>(new ReplaceVisitor().Modify(expression), Expression.Parameter(typeof(svc_JobAudit)));
return newExpression;
}
}
class ReplaceVisitor : ExpressionVisitor
{
public Expression Modify(Expression expression)
{
return Visit(expression);
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type == typeof(string))
{
return Expression.Property(Expression.Parameter(typeof(svc_JobAudit)), "JobName");
}
return node;
}
}
}
[wymienić parametr ekspresji lambda] (http://stackoverflow.com/questions/11159697/replace-parameter-in-lambda-expression) –