Usar un ExpressionVisitor de LINQ para reemplazar parámetros primitivos con referencias de propiedad en una expresión lambda

Estoy en el proceso de escribir una capa de datos para una parte de nuestro sistema que registra información sobre los trabajos automatizados que se ejecutan todos los días: el nombre del trabajo, la duración del mismo, el resultado, etc.

Estoy hablando con la base de datos utilizando Entity Framework, pero estoy tratando de mantener esos detalles ocultos de los módulos de nivel superior y no quiero que los objetos de la entidad estén expuestos.

Sin embargo, me gustaría hacer que mi interfaz sea muy flexible en los criterios que utiliza para buscar información sobre el trabajo. Por ejemplo, una interfaz de usuario debería permitir al usuario ejecutar consultas complejas como "dame todos los trabajos llamados 'hola' que se ejecutaron entre las 10:00 am y las 11:00 am que fallaron". Obviamente, esto parece un trabajo para construir dinámicamenteExpression arboles

Entonces, lo que me gustaría que mi capa de datos (repositorio) pudiera hacer es aceptar expresiones de tipo LINQExpression<Func<string, DateTime, ResultCode, long, bool>> (expresión lambda) y luego entre bambalinas convierte ese lambda en una expresión que mi Entity FrameworkObjectContext Se puede usar como filtro dentro de unWhere() cláusula.

En pocas palabras, estoy tratando de convertir una expresión lambda de tipoExpression<Func<string, DateTime, ResultCode, long, bool>> aExpression<Func<svc_JobAudit, bool>>, dóndesvc_JobAudit es el objeto de datos de Entity Framework que corresponde a la tabla donde se almacena la información del trabajo. (Los cuatro parámetros en el primer delegado corresponden al nombre del trabajo, cuándo se ejecutó, el resultado y el tiempo que tomó MS) respectivamente.

Estaba haciendo muy buen progreso usando elExpressionVisitor clase hasta que golpeé una pared de ladrillo y recibí unaInvalidOperationException con este mensaje de error:

Cuando se llama desde 'VisitLambda', al volver a escribir un nodo de tipo 'System.Linq.Expressions.ParameterExpression' debe devolver un valor no nulo del mismo tipo. Alternativamente, anule 'VisitLambda' y cámbielo para no visitar a niños de este tipo.

Estoy completamente desconcertado. ¿Por qué diablos no me permite convertir nodos de expresión que hacen referencia a parámetros a nodos que hacen referencia a propiedades? ¿Hay otra manera de hacer esto?

Aquí hay un código de ejemplo:

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

Respuestas a la pregunta(2)

Su respuesta a la pregunta