2012-02-09 45 views
3

我有這樣的控制方法:過濾通過Where子句,只有當條件不爲空

public ActionResult Index(string searchError) 
{ 
    // get all errors 
    var viewModel = _errorsRepository.Errors.OrderByDescending(e => e.TimeUtc). 
          Select(e => new ErrorViewModel 
              { 
               ErrorId = e.ErrorId, 
               Message = e.Message, 
               TimeUtc = e.TimeUtc 
              }); 

    if (!String.IsNullOrEmpty(searchError)) 
      viewModel = viewModel.Where(e => e.Message.ToLower().Contains(searchError.Trim().ToLower())); 

    return View(viewModel); 
} 

我覺得做額外的過濾器被拖慢的一切,我在想,如果我可以在WHERE子句添加到選擇聲明並檢查searchError是否爲內聯。

這可能嗎?

回答

7

因爲Linq是懶惰的,所以如果你有「一個大的語句」或多個,並不重要,只要你不執行你的查詢(例如通過遍歷結果或迫使使用ToList()急於執行)因爲你只是鏈接擴展方法而受到懲罰。在這方面,我會專注於可讀性。

雖然有些事情需要考慮,例如排序不能懶惰(您必須先查看所有項目,然後才能按順序排出項目) - 這就是爲什麼您應始終將您的Where篩選器放在OrderBy之前,這樣您的項目排序就會減少。這說我重組你這樣的代碼:

// get all errors 
var viewModel = _errorsRepository.Errors; 

// optionally filter    
if (!String.IsNullOrEmpty(searchError)) 
{ 
    string searchErrorMatch = searchError.Trim().ToLower(); 
    viewModel = viewModel.Where(e => e.Message.ToLower().Contains(searchErrorMatch)); 
} 

//order and project to ErrorViewModel 
viewModel = viewModel.OrderByDescending(e => e.TimeUtc) 
        .Select(e => new ErrorViewModel 
         { 
          ErrorId = e.ErrorId, 
          Message = e.Message, 
          TimeUtc = e.TimeUtc 
         }).ToList(); 

另外請注意,我掏出searchError.Trim().ToLower()你的拉姆達並將其分配給一個變量一次 - 每次拉姆達進行評估,否則就執行,這真的是不必要的工作。

最後編輯:我還添加了一個ToList()執行您的投影后的查詢 - 否則你的查詢真正會從你的觀點可以被執行,一般是不好的原因有很多,例如您必須保持數據庫上下文長時間存活,並且您違反了關注點分離 - 視圖只應關注視圖模型,但與獲取數據無關。

+0

夥計,這就是我所說的一個很好的答案。 – ivowiblo 2012-02-09 04:17:22

1

如果你真的想沒有if聲明一下子構建查詢,你可以把它寫像這樣...

public ActionResult Index(string searchError) 
{ 
    // get all errors 
    var viewModel = _errorsRepository.Errors.OrderByDescending(e => e.TimeUtc) 
     .Where(e => String.IsNullOrEmpty(searchError) 
        || e.Message.ToLower().Contains(searchError.Trim().ToLower()) 
     ).Select(
      e => new ErrorViewModel { 
       ErrorId = e.ErrorId, 
       Message = e.Message, 
       TimeUtc = e.TimeUtc 
      } 
     ); 

    return View(viewModel); 
} 

...但隨後在searchError是這樣null或您已經介紹了必須爲結果集中的每個項目調用的額外代理。最好讓代碼保持原樣,或者像BrokenGlass所建議的那樣,先進行過濾,然後對剩餘的項目進行排序,項目等。這實際上是關於LINQ能夠動態地插入不同方法並且僅使用實際需要的片斷來編寫查詢的非常酷的事情之一,並且它被全部評估爲懶惰(儘可能地)!