Я нахожусь в процессе написания слоя данных для части нашей системы, которая регистрирует информацию о автоматизированных заданиях, которые запускаются каждый день - имя задания, как долго оно работает, каков результат и т.д.
Я говорю с базой данных, используя Entity Framework, но я пытаюсь скрыть эти детали от модулей более высокого уровня, и я не хочу, чтобы сами объекты объектов были открыты.
Однако я хотел бы сделать мой интерфейс очень гибким в критериях, которые он использует для поиска информации о работе. Например, пользовательский интерфейс должен позволить пользователю выполнять сложные запросы, такие как "дать мне все задания с именем" hello ", которые выполнялись с 10:00 до 11:00, что не удалось". Очевидно, что это выглядит как работа для динамически построенных деревьев Expression
.
Так что я хотел бы, чтобы мой уровень данных (репозиторий) был в состоянии сделать, это принять выражения LINQ типа Expression<Func<string, DateTime, ResultCode, long, bool>>
(выражение lambda), а затем за кадром преобразовать этот лямбда в выражение, которое моя Entity Framework ObjectContext
может использоваться как фильтр внутри предложения Where()
.
Вкратце, я пытаюсь преобразовать лямбда-выражение типа Expression<Func<string, DateTime, ResultCode, long, bool>>
в Expression<Func<svc_JobAudit, bool>>
, где svc_JobAudit
- объект данных Entity Framework, который соответствует таблице, в которой хранится информация о задании. (Четыре параметра в первом делетете соответствуют имени задания, при его запуске, результату и длительности в MS соответственно)
Я делал очень хороший прогресс, используя класс ExpressionVisitor
, пока не ударил кирпичную стену и получил сообщение InvalidOperationException
с этим сообщением об ошибке:
При вызове из "VisitLambda" переписывание типа node'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;
}
}
}