Estoy escribiendo una capa de datos para una parte de nuestro sistema que registra información sobre trabajos automatizados que se ejecutan todos los días: nombre del trabajo , cuánto tiempo funcionó, cuál fue el resultado, etc.Uso de LINQ ExpressionVisitor para reemplazar parámetros primitivos con referencias de propiedad en una expresión lambda
Estoy hablando con la base de datos utilizando Entity Framework, pero trato de mantener esos detalles ocultos de los módulos de nivel superior y no quiero que la entidad se objeta a sí misma para estar expuesta.
Sin embargo, me gustaría que mi interfaz sea muy flexible en los criterios que utiliza para buscar información de trabajo. Por ejemplo, una interfaz de usuario debería permitir al usuario ejecutar consultas complejas como "darme todos los trabajos llamados 'hola' que se ejecutaron entre las 10:00 a.m. y las 11:00 a.m. que fallaron". Obviamente, esto parece un trabajo para árboles Expression
construidos dinámicamente.
Así que lo que me gustaría que mi capa de datos (repositorio) para ser capaz de hacer es aceptar expresiones LINQ de tipo Expression<Func<string, DateTime, ResultCode, long, bool>>
(expresión lambda) y luego detrás de las escenas que se convierten en una expresión lambda que mi marco de la entidad ObjectContext
puede utilizar como un filtro dentro de una cláusula Where()
.
En pocas palabras, estoy tratando de convertir una expresión lambda del tipo Expression<Func<string, DateTime, ResultCode, long, bool>>
a Expression<Func<svc_JobAudit, bool>>
, donde svc_JobAudit
es el objeto de datos de Entity Framework que corresponde a la mesa 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 cuánto tiempo llevó en MS, respectivamente)
Estaba haciendo un buen progreso utilizando la clase ExpressionVisitor
hasta que toco una pared de ladrillo y recibió una InvalidOperationException
con este mensaje de error:
cuando se llama desde 'VisitLambda', la reescritura de un nodo de tipo 'System.Linq.Expressions.ParameterExpression' debe devolver un valor no nulo de la el mismo tipo. Alternativamente, anule 'VisitLambda' y cámbielo para no visitar los niños de este tipo.
Estoy completamente desconcertado. ¿Por qué diablos no me permitirá convertir los nodos de expresión que los parámetros de referencia a los nodos que hacen referencia a las propiedades? ¿Hay alguna otra manera de hacerlo?
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;
}
}
}
[Reemplazar parámetro en la expresión lambda] (http://stackoverflow.com/questions/11159697/replace-parameter-in-lambda-expression) –