2012-02-09 2 views
3

У меня есть этот метод контроллера:Фильтрация по ИНЕК только тогда, когда условие не является нулевым

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

Я думаю, что делает дополнительный фильтр замедляет все вниз, мне было интересно, если я могу добавить, где положение в Select оператора и проверить, является ли searchError null inline.

Возможно ли это?

ответ

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

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 или empty вы представили дополнительный делегат, который должен быть вызван для каждого элемента в наборе результатов. Лучше оставить свой код так, как он есть, или, как предлагает BrokenGlass, сначала выполнить фильтрацию, а затем отсортировать, выполнить проект и т. Д. Оставшиеся элементы. На самом деле это одна из очень интересных вещей о том, что LINQ может динамически подключать различные методы и составлять запросы, используя только те части, которые вам действительно нужны, и все это лениво оценивается (насколько это возможно)!

Смежные вопросы