2015-02-05 3 views
1

У меня есть следующий метод:Создание WHERE условие с несколькими столбцами

protected override List<Contractor> GetSearchResults() 
{ 
    List<User> users = UnitOfWork.UserRepository.Get(
      user => 
      (!String.IsNullOrEmpty(FirstName) && user.FirstName.Contains(FirstName)) && 
      (!String.IsNullOrEmpty(LastName) && user.LastName.Contains(LastName))) 
      .ToList(); 
    return users ; 
} 

Это просто «упрощенный» пример. На самом деле у меня есть еще несколько «столбцов» для моего условия.

Оба «условия» связаны с оператором и (& &). Это означает, что:

  • Имя должно быть заполнено & должны соответствовать И
  • Второе название должно быть заполнены & должны соответствовать

Это не совсем то, что я хочу. Изменение кода с использованием или-оператора (||), как

protected override List<Contractor> GetSearchResults() 
{ 
    List<User> users = UnitOfWork.UserRepository.Get(
      user => 
      (!String.IsNullOrEmpty(FirstName) && user.FirstName.Contains(FirstName)) || 
      (!String.IsNullOrEmpty(LastName) && user.LastName.Contains(LastName))) 
      .ToList(); 
    return users ; 
} 

не обеспечивает желаемое решение, потому что:

  • Имя должно быть заполнено & должны соответствовать ИЛИ
  • Второе имя должно быть заполнено &

Итак, что мне нужно?

Например, если я должен следующие записи в моей базе данных:

  • Белый, Пол
  • Миллер, Джон
  • Миллер, Lea

Я ожидаю, что следующие результаты:

  • Если только фамилия "Миллер" является я хотел бы получить две записи .
  • Если введены фамилия и имя («Миллер» и «Джон»), я ожидаю получить только одну запись.

Мои условия просто не соответствуют этим требованиям, и я не знаю, как «просто» их изменить.

Будет ли это подходит лучше:

protected override List<Contractor> GetSearchResults() 
{ 
    List<User> users = UnitOfWork.UserRepository.Get(
      user => 
      (String.IsNullOrEmpty(FirstName) || (!String.IsNullOrEmpty(FirstName) && user.FirstName.Contains(FirstName))) && 
      (String.IsNullOrEmpty(LastName) || (!String.IsNullOrEmpty(LastName) && user.LastName.Contains(LastName)))) 
      .ToList(); 
    return users ; 
} 

Это похоже на работу. Но с большим количеством столбцов он определенно выглядит уродливым и его трудно читать. Есть ли способ упростить эту задачу?

+0

Я верю '(String.IsNullOrEmpty (FirstName) || (! String.IsNullOrEmpty (FirstName) && user.FirstName.Contains (FirstName)))' может быть упрощено до 'user.FirstName.Contains ((FirstName ?? "")) '. –

ответ

0

Я думаю, вы можете упростить свой последний кусок кода, чтобы что-то вроде:

List<User> users = UnitOfWork.UserRepository.Get(
      user => 
      (String.IsNullOrEmpty(FirstName) || user.FirstName.Contains(FirstName)) && 
      (String.IsNullOrEmpty(LastName) || user.LastName.Contains(LastName)) 
      ).ToList(); 
0

В качестве начала, вы можете создать вспомогательную функцию, чтобы получить условные из основного кода

public bool FilterColumn(string columnData, string filterData) 
{ 
    return String.IsNullOrEmpty(filterData) || columnData.Contains(filterData); 
} 

, который затем может быть использован как этот

List<User> users = UnitOfWork.UserRepository.Get(
      user => FilterColumn(user.FirstName, FirstName) && 
        FilterColumn(user.LastName, LastName)).ToList() 

Если предположить, что этот код будет л imited путем ввода пользователем, вы можете также использовать отражение, чтобы помочь немного (при условии фильтра являются локальными по отношению к классу, как в приведенном выше примере)

private bool FilterColumn(User user, string columnName) 
    { 
    var filterValue = (string) GetType().GetProperty (columnName).GetValue (this); 
    var userValue = (string) GetType().GetProperty (columnName).GetValue (user); 

    return string.IsNullOrWhiteSpace (userValue) || userValue.Contains (filterValue); 
    } 

Тогда вы можете создать функцию агрегации для сбора столбцов

public bool FilterByColumnNames(User user, params string[] columns) 
    { 
    return columns.Aggregate (true, (result, columnValue) => FilterColumn (user, columnValue)); 
    } 

Этот метод может быть использован следующим образом

var result = FilterByColumnNames(User user, "FirstName", "LastName"); 

Теперь, это не очень рефакторинга дружны, мы построим еще некоторые вспомогательные функции, используя выражения

public String ToColumnName(Expression<Func<User,string>> column) 
    { 
    return ((MemberExpression)column.Body).Member.Name; 
    } 

    public bool FilterByColumns(User user, params Expression<Func<User,string>>[] columns) 
    { 
    return FilterByColumnNames (user, columns.Select (ToColumnName).ToArray()); 
    } 

, который затем может быть использован как этот

 var x = FilterByColumns (User, 
       u => u.FirstName, 
       u => u.LastName); 

Теперь, это неоптимизированная версия, вы можете быть в состоянии копать глубже в выражениях для создания оптимизированных версий выборок, если производительность является но для большинства вещей, связанных с типизацией пользователя, это должно быть достаточно быстро.