繁体   English   中英

Linq where子句“如果item不为null,则求值,否则,获取所有数据”

[英]Linq where clause “if item is not null, evaluate, otherwise, get all data”

我正在尝试在Web客户端上实现一个过滤器表单,该表单可以具有任意数量的项目,这些项目可以填写或为空。 我的WebAPI方法将采用包含表单所有属性的模型,就像这样:

RequisitionType (enum: RequisitionType.RequisitionedBy, RequisitionType.CreatedBy)
Vendor (string or null)
Plant (string or null)
CompanyCode (string or null)
CreatedFrom (datetime)
CreatedTo (datetime)

我如何在没有很多if (condition) { filter }实现linq查询?

我已经尝试过类似的方法,在该方法中,我首先检查过滤器是否有值,如果有,我将字段与该值进行比较,否则,我将字段与自身进行比较,但是编译器不允许这样做。

在下面的示例中, model是从客户端传递到控制器的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();

我认为最简单的方法是:

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调用函数所需的处理能力),但是IMHO可以提高可读性。

为了提高可读性,并且由于它几乎是相同数量的代码,我肯定会使用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);

...

不是完全遵循您的尝试,而是基于标题:

var data = logic.GetPurchaseReqs();

if(condition)
{
    data = data.Where(pr => pr.... etc
}

var result = data.ToList();

这就是我要编程的方式。 请注意缺少方括号以及我处理请购单类型的方式。 这假定申请单类型不能为空...如果可以的话...那么您必须添加第三个条件|| model.RequisitionType == null || model.RequisitionType == null 否则,您检查的每个条件都会作为另一个&& (condition != null ? conditionCheck : true)添加&& (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。

最好的解决方案是为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;
    }
}

现在,您可以执行条件where语句,而无需使用if语句。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM