Użycie LINQ ExpressionVisitor do zastąpienia pierwotnych parametrów odwołaniami do właściwości w wyrażeniu lambda

Jestem w trakcie pisania warstwy danych dla części naszego systemu, która rejestruje informacje o zautomatyzowanych zadaniach uruchamianych każdego dnia - nazwę zadania, czas jego trwania, wynik, itp.

Rozmawiam z bazą danych za pomocą Entity Framework, ale staram się ukryć te szczegóły przed modułami wyższego poziomu i nie chcę, aby obiekty encji same się ujawniały.

Chciałbym jednak, aby mój interfejs był bardzo elastyczny, jeśli chodzi o kryteria wyszukiwania informacji o pracy. 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 były uruchamiane między 10:00 a 11:00, które zakończyły się niepowodzeniem.” Oczywiście wygląda to jak zadanie dla dynamicznie zbudowanychExpression drzewa.

Tak więc, co chciałbym, aby moja warstwa danych (repozytorium) była w stanie akceptować wyrażenia typu LINQExpression<Func<string, DateTime, ResultCode, long, bool>> (wyrażenie lambda), a następnie za kulisami przekonwertuj tę lambdę na wyrażenie, które moja struktura encjiObjectContext może służyć jako filtr wewnątrz aWhere() klauzula.

W skrócie próbuję przekonwertować wyrażenie lambda typuExpression<Func<string, DateTime, ResultCode, long, bool>> doExpression<Func<svc_JobAudit, bool>>, gdziesvc_JobAudit jest obiektem danych Entity Framework, który odpowiada tabeli, w której przechowywane są informacje o zadaniu. (Cztery parametry w pierwszym delegacie odpowiadają nazwie zadania, gdy było uruchomione, wynikowi i czasowi, jaki zajęło odpowiednio w MS)

Robiłem bardzo dobre postępy, używającExpressionVisitor klasa, dopóki nie uderzę w ścianę z cegieł i nieInvalidOperationException z tym komunikatem o błędzie:

Po wywołaniu z „VisitLambda”, przepisanie węzła typu „System.Linq.Expressions.ParameterExpression” musi zwrócić wartość inną niż null tego samego typu. Alternatywnie, zastąp „VisitLambda” i zmień go, aby nie odwiedzać dzieci tego typu.

Jestem całkowicie zaskoczony. Dlaczego do cholery nie pozwoli 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 jest inny sposób na to?

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

questionAnswers(2)

yourAnswerToTheQuestion