2012-02-09 125 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能够动态地插入不同方法并且仅使用实际需要的片断来编写查询的非常酷的事情之一,并且它被全部评估为懒惰(尽可能地)!