使用 LINQ select 有条件地忽略字段

Conditionally ignore fields with LINQ select

我一直找不到任何示例,您可以在这些示例中根据 LINQ 中的 select 投影中的变量有条件地排除字段,另请参阅 LINQ: Select an object and change some properties without creating a new object

让我介绍一下我要实现的目标的背景知识。我想根据用户是否可以编辑数据(即评论字段)来限制从模型中设置的 DTO 中的某些字段。例如,以下 select 具有名为 CustomerView 的委托。

var qry = _ctx.Customer.Select(CustomerView(User.IsInRole("Editor")));

Customer 模型有一个 Orders 导航 属性,以下函数将数据转换为 CusomerViewModel DTO。

private Expression<Func<Customer, CustomerViewModel>> CustomerView(bool isEditor) {
    return c => new CustomerViewModel
    {
        Id = c.Id,
        Name = c.Name,
        Comment = isEditor ? c.Comment : null,
        OrderCount = c.Orders.Count()
    };
}

这将生成 SQL,就像 CASE WHEN @__isEditor_0 = TRUE THEN Comment ELSE NULL 一样有效,但我更希望表达式甚至不生成,即字段保留为默认值。这是一个简单的用例,但如果我想对 OrderCount 字段执行相同的操作,SQL 子查询仍会包含在内。

当然,我可以为非编辑器用户创建另一个排除某些字段的函数,但我宁愿没有单独的预测来维护,尤其是当它们更复杂时。

我看到动态 LINQ 用于 where 子句但没有那么多用于 select 的问题。这种做法可行吗?

编辑:在使用 select 之后,是否可以通过扩展方法从表达式树中手动删除字段?

使用 LINQKit 我能够通过将 AsExpandable() 添加到 select 来实现预期的结果。

var qry = _ctx.Customer.AsExpandable().Select(CustomerView(User.IsInRole("Editor")));

然后为评论字段添加表达式并在字段赋值时调用Invoke()

private Expression<Func<Customer, CustomerViewModel>> CustomerView(bool isEditor) {
    Expression<Func<Customer, string>> exprComment;
    if (isEditor)
        exprComment = c => c.Comment;
    else
        exprComment = c => null;

    return c => new CustomerViewModel
    {
        Id = c.Id,
        Name = c.Name,
        Comment = exprComment.Invoke(c),
        OrderCount = c.Orders.Count()
    };
}

它确实有效,但我仍然有兴趣了解任何替代方法。