我正在尝试在Web客户端上实现一个过滤器表单,该表单可以填写任何数量的项目或为空。我的WebAPI方法将采用一个模型,该模型是表单的所有属性,它将类似于:
RequisitionType (enum: RequisitionType.RequisitionedBy, RequisitionType.CreatedBy)
Vendor (string or null)
Plant (string or null)
CompanyCode (string or null)
CreatedFrom (datetime)
CreatedTo (datetime)
如何实现linq查询而不会有很多疯狂的if (condition) { filter }
?
我尝试过这样的事情,我首先检查过滤器是否有值,如果是,我会将字段与该值进行比较,否则我会将字段与自身进行比较,但编译器不是允许这样做。
在下面的示例中,model
是从客户端传递给控制器的内容。
var data = logic.GetPurchaseReqs()
.Where(pr => {
model.RequisitionType == RequisitionType.RequisitionedBy ? pr.PrReqId.ToUpper() == model.Username.ToUpper() : pr.PrReqId.ToUpper() == pr.PrReqId.ToUpper()
&& model.RequisitionType == RequisitionType.CreatedBy ? pr.PrCreId.ToUpper() == model.Username.ToUpper() : pr.PrCreId.ToUpper() == pr.PrCreId.ToUpper()
&& model.Vendor != null ? pr.Vendor == model.Vendor : pr.Vendor == pr.Vendor
[etc...]
})
.ToList();
答案 0 :(得分:3)
我认为最简单的方法是:
logic.GetPurchaseReqs()
.Where(pr => model.RequisitionType != RequisitionType.RequisitionedBy || pr.PrReqId.ToUpper() == model.Username.ToUpper())
.Where(pr => model.RequisitionType != RequisitionType.CreatedBy || pr.PrCreId.ToUpper() == model.Username.ToUpper())
.Where(pr => model.Vendor == null || pr.Vendor == model.Vendor)
//[...]
.ToList();
请注意,添加几个Where
子句会产生微不足道的开销(只是JIT调用函数所需的处理能力),但是恕我直言提高了可读性。
答案 1 :(得分:3)
为了便于阅读,由于代码数量几乎相同,我肯定会使用if(condition)
解决方案。
var data = logic.GetPurchaseReqs(); //.AsEnumerable() migt be needed here
if(model.RequisitionType == RequisitionType.RequisitionedBy)
data = data.Where(pr => pr.PrReqId.ToUpper() == model.Username.ToUpper())
if(model.Vendor != null)
data = data.Where(pr => pr.Vendor == model.Vendor);
if(model.CompanyCode != null)
data = data.Where(pr => pr.CompanyCode == model.CompanyCode);
...
答案 2 :(得分:1)
根据您的标题,不完全遵循您的目标:
var data = logic.GetPurchaseReqs();
if(condition)
{
data = data.Where(pr => pr.... etc
}
var result = data.ToList();
答案 3 :(得分:0)
这就是我编程的原因。请注意缺少括号和处理申请类型的方式。这假定请购单类型不能为空...如果它可以...那么你必须添加第三个条件|| model.RequisitionType == null
。否则,您检查的每个条件都会被添加为另一个&& (condition != null ? conditionCheck : true)
var data = logic.GetPruchaseReqs().Where(pr =>
((model.RequisitionType == RequisitionType.RequisitionedBy && pr.PrReqId.Equals(model.Username, StringComparison.InvariantCultureIgnoreCase)) || (model.RequisitionType == RequisitionType.CreatedBy && pr.PrCreId.Equals(model.Username, StringComparison.InvariantCultureIgnoreCase)))
&& (model.Vendor != null ? pr.Vendor.Equals(model.Vendor) : true)
&& (condition != null ? conditionCheck : true)).ToList();
目标是设置=>的右侧。评估一个布尔值true / false。您应该能够为(pr)的任何给定值评估该语句,并获得true或false。
答案 4 :(得分:-1)
最好的解决方案是为linq创建一个扩展方法。它将接受一个条件语句和where表达式,如果条件为true,它将使用where表达式,否则它将跳过它。这可以大大清理代码,无需if语句。
public static class LinqExtension
{
public static IQueryable<T> Where<T>(this IQueryable<T> query, bool condition, Expression<Func<T, bool>> whereClause)
{
if (condition)
{
return query.Where(whereClause);
}
return query;
}
}
现在你可以在不使用if语句的情况下执行条件where语句。
var data = logic.GetPurchaseReqs()
.Where(model.RequisitionType == RequisitionType.RequisitionedBy, pr => pr.PrReqId.ToUpper() == model.Username.ToUpper())
.Where(model.Vendor != null, pr => pr.Vendor == model.Vendor)
.Where(model.CompanyCode != null, pr => pr.CompanyCode == model.CompanyCode);