我无法找到任何示例,可以在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,但我希望甚至不生成该表达式,即默认保留字段。这是一个简单的用例,但是如果我想对OrderCount字段执行相同的操作,则仍将包含SQL子查询。
当然,我可以为非编辑者用户创建另一个函数,该函数排除某些字段,但是我宁愿没有单独的投影来维护,尤其是当它们更复杂时。
我看到问题,其中动态LINQ用于where子句,但对于select子句却不多。这种方法可行吗?
Edit:在使用了选择之后,是否可以通过扩展方法手动从表达式树中删除字段?
使用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()
};
}
它似乎确实有效,但是我仍然想听听其他方法。