Добавление в Lambda Expression и работа с Entity Framework
Если я хочу получить больше столбцов с уже существующим выражением лямбда-дерева, как показано ниже, как мне это сделать? Это работает с Entity Frameworks и хочет, чтобы оно все еще работало.
Expression<Func<DivisionTeam, DirectorTeamModel>> columns= (d) => new DirectorTeamModel
{
Id = d.Id,
TeamId = d.Team.Id
};
if (criteria.Template == ExportTemplate.Import || criteria.Template == ExportTemplate.Default)
{
// Retrieve additional columns from "columns" expression tree
}
return _divisionTeamsRepository.GetPagedResults(criteria.Page, criteria.PageSize, @where.Expand(), string.Format("{0} {1}", criteria.SortOrder, criteria.SortDirection), columns);
1 ответ
Учитывая два выражения "селектор", вы должны взять привязки из их MemberInitExpression
и создайте новое выражение, используя все привязки. Но это выражение не будет работать, так как оно использует два разных выражения параметра для одного параметра. Нам тоже нужно это исправить.
Дано...
Expression<Func<TSource, TResult>> left = ... // columns
Expression<Func<TSource, TResult>> right = ... // more columns
... взять привязки...
var leftInit = left.Body as MemberInitExpression;
var rightInit = right.Body as MemberInitExpression;
var bindings = leftInit.Bindings.Concat(rightInit.Bindings);
... создать новое выражение...
var result = Expression.Lambda<Func<TSource, TResult>>(
Expression.MemberInit(Expression.New(typeof(TResult)), bindings), ???);
... НО, нужен один параметр...
var binder = new ParameterBinder(left.Parameters[0], right.Parameters[0]);
var bindings = binder.Visit(leftInit.Bindings.Concat(rightInit.Bindings));
// now, just use right.Parameters[0] as parameter...
И замена параметров работает хорошо с помощью посетителя выражения:
class ParameterBinder : ExpressionVisitor
{
readonly ParameterExpression parameter;
readonly Expression replacement;
public ParameterBinder(ParameterExpression parameter, Expression replacement)
{
this.parameter = parameter;
this.replacement = replacement;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node == parameter)
return replacement;
return base.VisitParameter(node);
}
}
Абстрагирование этого сантехника работает довольно хорошо. На самом деле, вы можете просто использовать существующую библиотеку (спойлер: я автор), что должно привести к чему-то вроде этого:
var merged = columns.Apply(moreColumns);