логическое выражение для Where

#c# #.net #entity-framework

#c# #.net #entity-framework

Вопрос:

Я фильтрую данные, используя обнуляемую переменную.
Если переменная равна null, фильтр отключен.
Есть ли более приятный способ написать:

 GetQuery().Where(pd=> (!customerId.HasValue || pd.CustomerId==customerId.Value))
  

(У меня более 4 фильтров, и это выглядит как огромный блок беспорядка)

Ответ №1:

Ваш пример:

 GetQuery().Where(pd=> (!customerId.HasValue || pd.CustomerId==customerId.Value))
  

может быть написано с использованием оператора объединения null ?? :

 GetQuery().Where( pd => pd.CustomerID == ( customerId ?? pd.CustomerID ) )
  

Не уверен, что это что-то улучшает, но это вариант.

Комментарии:

1. Это интересно, хотя вы, я полагаю, имеете в виду, что вы customerId ?? pd.CustomerID заключены в скобки, иначе это было бы недопустимым выражением (в общем случае).

2. Интересно. Я бы подумал, ?? что привязка будет более жесткой, чем ==

Ответ №2:

Возможно, вы могли бы использовать метод расширения для его создания.

 public static IQueryable<T> OptionalWhere<T>(this IQueryable<T> query, int? id, Expression<Func<T, int, bool>> filter)
{
    if (id.HasValue)
    {
        var idValue = id.Value;
        query = query.Where(e => filter(e, idValue));
    }
    return query;
}
  

Затем запрос в становится:

 var q = GetQuery().OptionalWhere(customerId, (pd, id) => pd.CustomerId == id);
  

Комментарии:

1. Есть ли способ написать этот метод для каждого обнуляемого типа (long?, int?, string и так далее)?

2. @Naor Типы с нулевым значением (которые не включают string ) являются экземплярами Nullable<T> . Вы всегда можете задать тип id параметра Nullable<T> (хотя, опять же, это не поможет вам работать со строками).

3. Вы не можете волшебным образом вызвать подобное выражение … вам пришлось бы его перестроить.

Ответ №3:

Нет, лучшего способа написать то же самое не существует. Однако я должен сказать, что для нужной вам логики (что не является стандартным значением null в обнуляемом типе) оно довольно короткое. Я не думаю, что вы можете ожидать, что оно станет короче.

Я не нахожу его особенно нечитаемым или беспорядочным, даже если у вас было 4 или даже 10 копий этой строки друг под другом. Самое короткое, о чем я могу подумать, это:

 GetQuery().Where(pd => customerId == null || pd.CustomerId == customerId)
          .Where(pd => customerName == null || pd.CustomerName == customerName)
          .Where(pd => customerAddress == null || pd.CustomerAddress == customerAddress)
          .Where(pd => customerPostcode == null || pd.CustomerPostcode == customerPostcode)
          .Where(pd => customerCountry == null || pd.CustomerCountry == customerCountry)
          .Where(pd => customerPhoneNumber == null || pd.CustomerPhoneNumber == customerPhoneNumber)
  

Комментарии:

1. Я на самом деле использовал . Где(pd=> … amp;amp; … amp;amp; …) а не Where для каждого условия. Влияет ли это на эффективность?

2. @Naor: Это не имеет заметного значения. Если это LINQ-to-SQL, то это даже вообще не имеет никакого значения.

3. Я не могу говорить об эффективности, но я бы определенно связал методы расширения LINQ в цепочку, прежде чем объединять большое количество условий в одном анонимном предикате…