Как изменить тип дерева выражений и правильно обновить вложенные выборки в нем?
Я использую Entity Framework 6.3 и Visual Studio 2017. Допустим, у меня есть следующие классы.
class Store
{
//Some other fields
List<Toy> Toys = new List<Toy>();
List<Item> SoldItems = new List<Item>();
}
class Toy
{
//Some other fields
List<Order> Orders = new List<Order>();
}
class Order
{
//Some other fields
}
class Item
{
//Some other fields
}
Я знаю, что эти занятия не имеют особого смысла, но, надеюсь, их будет достаточно, чтобы выявить проблему.
У меня также есть метод, который выглядит следующим образом:
IEnumerable<TEntity> FindByAndInclude(Expression<Func<TEntity, bool>> predicate,
params Expression<Func<TEntity, object>>[] includeProperties)
{
var query = includeProperties.Aggregate(_dbSet.AsQueryable(), (current, includeProperty) => current.Include(includeProperty));
return query.Where(predicate).AsNoTracking().ToList();
}
Где _dbSet определен как DbSet
Stores.FindByAndInclude(x => x.StoreName.Equals(_StoreName),
t => t.toys.
Select(o => o.Orders),
i => i.SoldItems));
И это прекрасно работает. Проблема возникла, когда я попытался ввести новый набор классов, назовем их Store1, Toy1, Order1, Item1 с одинаковыми полями (поля имеют одинаковые имена, но соответствующие типы). Пример:
class Toy
{
List<Order1> Orders = new List<Order1>();
}
Эти классы содержат мои аннотации Entity Framework, поэтому я хочу использовать их для запроса и сохранения данных, а также хочу использовать классы, определенные в приведенном выше фрагменте кода клиента.
Поэтому теперь метод FindByInclude не будет работать, поскольку я передаю выражение
До сих пор мне удалось преобразовать предикат из Expression > в Expression
class ExpressionFixer<T> : ExpressionVisitor
{
ParameterExpression _parameter;
public ExpressionFixer(ParameterExpression parameter)
{
_parameter = parameter;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return _parameter;
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.MemberType == System.Reflection.MemberTypes.Property)
{
MemberExpression memberExpression = null;
var memberName = node.Member.Name;
var otherMember = typeof(T).GetProperty(memberName);
memberExpression = Expression.Property(Visit(node.Expression), otherMember);
return memberExpression;
}
else
{
return base.VisitMember(node);
}
}
}
И я использую его в своем коде так:
var param = Expression.Parameter(typeof(SEntity), typeof(SEntity).ToString());
var result = new ExpressionFixer<SEntity>(param).Visit(source.Body);
Expression<Func<SEntity, bool>> expression = Expression.Lambda<Func<SEntity, bool>>(result, param);
_dbSet.Where(expression).ToList();
Опять же, это работает, но я не могу понять, как сделать то же самое для includeProperties. Код, который я нашел для моего метода FindByInclude, теперь выглядит следующим образом:
List<Expression<Func<SEntity, object>>> tempList = new List<Expression<Func<SEntity, object>>>();
foreach(var property in includeProperties)
{
var param = Expression.Parameter(typeof(SEntity), typeof(SEntity).ToString());
var result = new ExpressionFixer<SEntity>(param).Visit(source.Body);
Expression<Func<SEntity, bool>> expression =Expression.Lambda<Func<SEntity, object>>(result, param);
tempList.Add(expression);
}
Expression<Func<SEntity, object>>[] fixedIncludeProperties = tempList.ToArray();
var query = fixedIncludeProperties.Aggregate(_dbSet.AsQueryable(), (current, includeProperty) => current.Include(includeProperty));
// Executing the query and mapping results back to TEntity type
Но этот код вызывает исключение System.ArgumentException:
'ParameterExpression типа'Toy1'нельзя использовать для параметра делегата типа'Order''
когда я пытаюсь запустить его для:
Stores.FindByAndInclude(x => x.StoreName.Equals(_StoreName),
t => t.Toys.
Select(o => o.Orders);
Я понимаю, что мне нужно каким-то образом обновить типы заказов, но я просто не знаю, как, потому что я не знаю, как хорошо ориентироваться в выражениях. Итак, наконец, мой вопрос, как это выполнимо? (А поскольку я впервые пытаюсь что-то подобное), что может быть лучше? Суть задачи состоит в том, чтобы иметь две версии классов, поэтому менять их нельзя.