Использование LINQ ExpressionVisitor для замены параметров примитива ссылками на свойства в лямбда-выражении
Я нахожусь в процессе написания слоя данных для части нашей системы, которая регистрирует информацию об автоматизированных заданиях, которые выполняются каждый день - название задания, как долго оно выполнялось, каков был результат и т. Д.
Я разговариваю с базой данных с использованием Entity Framework, но я пытаюсь скрыть эти детали от модулей более высокого уровня и не хочу, чтобы сами объекты сущности были открыты.
Тем не менее, я хотел бы сделать мой интерфейс очень гибким по критериям, которые он использует для поиска информации о работе. Например, пользовательский интерфейс должен позволять пользователю выполнять сложные запросы, такие как "дать мне все задания с именем" привет ". который проходил с 10:00 до 11:00, что не удалось. & quot; Очевидно, это выглядит как работа для динамическиExpression
деревья.
Поэтому мне хотелось бы, чтобы мой уровень данных (хранилище) мог принимать выражения типа LINQExpression<Func<string, DateTime, ResultCode, long, bool>>
(лямбда-выражение), а затем за кулисами преобразовать эту лямбда-выражение в выражение, которое моя Entity FrameworkObjectContext
можно использовать в качестве фильтра внутриWhere()
пункт.
Короче говоря, я пытаюсь преобразовать лямбда-выражение типаExpression<Func<string, DateTime, ResultCode, long, bool>>
вExpression<Func<svc_JobAudit, bool>>
, гдеsvc_JobAudit
является объектом данных Entity Framework, который соответствует таблице, в которой хранится информация о задании. (Четыре параметра в первом делегате соответствуют названию задания, времени его выполнения, результату и времени выполнения в MS соответственно)
Я делал очень хорошие успехи, используяExpressionVisitor
класс, пока я не ударил кирпичную стену и не получилInvalidOperationException
с этим сообщением об ошибке:
When called from 'VisitLambda', rewriting a node of type 'System.Linq.Expressions.ParameterExpression' must return a non-null value of the same type. Alternatively, override 'VisitLambda' and change it to not visit children of this type.
Я полностью сбит с толку. Почему, черт возьми, это не позволяет мне преобразовывать узлы выражения, которые ссылаются на параметры, в узлы, которые ссылаются на свойства? Есть ли другой способ пойти по этому поводу?
Вот пример кода:
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;
}
}
}