簡體   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