If I want retrieve more columns with an already existing lambda tree expression like below, how would I do that? This works with Entity Frameworks and want it to still work.
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);
Given two "selector" expressions, you've to take the bindings from their MemberInitExpression
and create a new expression using all the bindings. But this expression isn't going to work, since it uses two different parameter expressions for one single parameter. We need to fix that too.
Given...
Expression<Func<TSource, TResult>> left = ... // columns
Expression<Func<TSource, TResult>> right = ... // more columns
...take the bindings...
var leftInit = left.Body as MemberInitExpression;
var rightInit = right.Body as MemberInitExpression;
var bindings = leftInit.Bindings.Concat(rightInit.Bindings);
...create a new expression...
var result = Expression.Lambda<Func<TSource, TResult>>(
Expression.MemberInit(Expression.New(typeof(TResult)), bindings), ???);
...BUT, need single parameter...
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...
And, replacing parameters works well using an expression visitor:
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);
}
}
Abstracting this plumbing stuff works quite well. In fact, you can just use an existing library (spoiler: I'm the author), which should lead to something like that:
var merged = columns.Apply(moreColumns);
来源:https://stackoverflow.com/questions/43822899/adding-to-lambda-expression-and-work-with-entity-framework