Я в процессе написания слоя данных для части нашей системы, которая регистрирует информацию о автоматизированных заданиях, которые запускаются каждый день - имя задания , как долго это продолжалось, какой результат был и т. д.Использование LINQ ExpressionVisitor для замены примитивных параметров ссылками на свойства в выражении лямбда
Я обращаюсь к базе данных с помощью Entity Framework, но я пытаюсь скрыть эти детали от модулей более высокого уровня, и я не хочу, чтобы объекты объекта сами подвергаются воздействию.
Однако я хотел бы сделать мой интерфейс очень гибким в критериях, которые он использует для поиска информации о работе. Например, пользовательский интерфейс должен позволить пользователю выполнять сложные запросы, такие как «дать мне все задания с именем« hello », которые выполнялись с 10:00 до 11:00, что не удалось». Очевидно, это выглядит как работа для динамически построенных деревьев Expression
.
Так что я хочу, чтобы мой уровень данных (хранилище), чтобы быть в состоянии сделать, это принять LINQ выражения типа Expression<Func<string, DateTime, ResultCode, long, bool>>
(лямбда-выражения), а затем за кадром преобразования, что лямбда на выражение, что мой Entity Framework ObjectContext
может использовать как фильтр внутри предложения Where()
.
В двух словах, я пытаюсь преобразовать лямбда-выражения типа Expression<Func<string, DateTime, ResultCode, long, bool>>
к Expression<Func<svc_JobAudit, bool>>
, где svc_JobAudit
является объектом данных Entity Framework, который соответствует таблице, в которой хранится информация задания. (Четыре параметра в первом делетете соответствуют названию задания, при его запуске, результату и длительности в MS соответственно)
Я добился очень хорошего прогресса, используя класс ExpressionVisitor
, пока не ударил кирпичная стена и получила InvalidOperationException
с этим сообщением об ошибке:
при вызове из «VisitLambda», перезапись узла типа «System.Linq.Expressions.ParameterExpression» должен вернуть ненулевой значения из такой же тип. Альтернативно, переопределить 'VisitLambda' и изменить его, чтобы не посещать дочерние элементы этого типа.
Я полностью сбит с толку. Почему heck не позволяет мне преобразовать узлы выражения, которые ссылаются на узлы, которые ссылаются на свойства? Есть ли еще один способ сделать это?
Вот некоторые примеры кода:
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;
}
}
}
[параметр в лямбда-выражения Заменить] (http://stackoverflow.com/questions/11159697/replace-parameter-in-lambda-expression) –