在Lambda表达式中添加内容并与Entity Framework一起使用

4
如果我想在已经存在的lambda树表达式中检索更多的列,该怎么做? 这适用于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);

3
“columns = d => { var c = columns(); c.OtherProperty = d.OtherProperty; return c; }”存在什么问题?请具体说明你尝试了什么,以及你遇到的具体问题是什么。目前你的问题非常笼统。 - Peter Duniho
你不觉得我已经做过了吗?看起来你没有测试,因为你会得到这个错误:带有语句主体的 Lambda 表达式无法转换为表达式树。 - Mike Flynn
1
如果您想直接修改表达式,那么您可能会陷入痛苦的世界。即使这意味着复制第一个表达式并仅添加其他属性,但如果您创建一个全新的表达式,您的代码看起来会更加可读。 - DavidG
是的,我想那是我的最后选择,但我无法相信没有一个简单的解决方案。 - Mike Flynn
很可能是可以的,但需要大量的代码,手动创建MemberExpression,将它们添加到绑定中,对于每个要添加的附加属性都要这样做,然后无论如何都要创建一个新表达式,因为许多层次结构本身是不可变的。 - DavidG
显示剩余2条评论
1个回答

2
给定两个“选择器”表达式,您需要从它们的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);

@Mike 这有帮助吗?(您的悬赏将在2天内结束...) - Axel Heer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接