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

时间:2020-03-11 00:12:13

标签: linq entity-framework-core expression-trees dynamic-linq linqkit

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

让我就我要实现的目标提供一些背景知识。我想根据用户是否可以编辑数据来限制从模型设置的DTO中的某些字段(即注释字段)。例如,以下选择了一个名为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()
    };
}

这将生成像CASE WHEN @__isEditor_0 = TRUE THEN Comment ELSE NULL这样的SQL,该SQL可以工作,但是我更希望甚至不生成该表达式,即默认保留字段。那是一个简单的用例,但是如果我想对OrderCount字段做同样的事情,SQL子查询仍然会包含在内。

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

我看到了一些疑问,其中动态LINQ用于where子句,但对于select没有那么多。这种方法可行吗?

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

1 个答案:

答案 0 :(得分:0)

使用LINQKit可以通过添加AsExpandable()进行选择来达到预期的效果。

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()
    };
}

它看起来确实有效,但是我仍然想听听其他方法。