LINQ to SQL и пустые строки, как использовать «Содержит»?

Вот запрос

from a in this._addresses
where a.Street.Contains(street) || a.StreetAdditional.Contains(streetAdditional)
select a).ToList<Address>()

если оба свойства в предложении where имеют значения, это работает нормально, но если, например, a.StreetAdditional имеет значение null (в большинстве случаев), я получу исключение нулевой ссылки.

Есть ли работа вокруг этого?

Спасибо,


person Oakcool    schedule 10.06.2009    source источник
comment
Вы получили исключение? Или вы размышляете, чем возможно исключение?   -  person Amy B    schedule 10.06.2009
comment
Если у вас есть NullReferenceException для этого, вы не выполняете запрос LINQ to SQL.   -  person Pavel Minaev    schedule 29.11.2009
comment
Вы также можете подумать о том, чтобы не допускать, чтобы Street или StreetAdditional были нулевыми. Если ваш db поддерживает значения по умолчанию, вы можете по умолчанию использовать пустую строку, установить флаг, чтобы запретить нули и устранить необходимость нулевой проверки.   -  person Tod    schedule 13.12.2011
comment
Кстати, запрос работает в LinqPad. Как это возможно? Почему существует такая разница в поведении Linq to SQL между двумя инструментами?   -  person dpant    schedule 13.11.2015


Ответы (8)


Самый очевидный:

from a in this._addresses
where (a.Street != null && a.Street.Contains(street)) || (a.StreetAdditional != null && a.StreetAdditional.Contains(streetAdditional))
select a).ToList<Address>()

В качестве альтернативы вы можете написать метод расширения для Contains, который без ошибок принимает нулевой аргумент. Кто-то может сказать, что иметь такой метод не так уж и красиво, потому что он выглядит как обычный вызов метода, но разрешен для нулевых значений (таким образом отказываясь от обычных практик проверки нулей).

person driis    schedule 10.06.2009
comment
Пользовательские методы расширения нельзя использовать в LINQ to SQL. - person Pavel Minaev; 29.11.2009

Я бы использовал оператор объединения с нулевым значением...

(from a in this._addresses
where (a.Street ?? "").Contains(street) || (a.StreetAdditional ?? "").Contains(streetAdditional)
select a).ToList<Address>()
person Yuliy    schedule 10.06.2009
comment
Это более чистый подход. Идеально подходит для работы с IQueryable‹T› - person DanKodi; 28.07.2014

Вы должны сначала проверить, является ли StreetAdditional null.

Пытаться

where a.Street.Contains(street) || ((a != null) && a.StreetAdditional.Contains(streetAdditional))

Это работает, потому что && является оператором быстрого доступа, и если a != null дает false, второе выражение со значением null не будет вычисляться, поскольку результат все равно будет false.

person Dario    schedule 10.06.2009

Я бы создал метод расширения, чтобы возвращать пустую последовательность, если ноль, а затем вызов содержит метод.

public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> pSeq)
{
      return pSeq ?? Enumerable.Empty<T>();
}

from a in this._addresses
where a.Street.Contains(street) || 
      a.StreetAdditional.EmptyIfNull().Contains(streetAdditional)
select a).ToList<Address>()
person Vasu Balakrishnan    schedule 10.06.2009
comment
Выглядит несколько странно, потому что null-объекты, похоже, могут вызывать функции-члены. - person Dario; 10.06.2009
comment
Проголосовать за использование знака ?? оператор. Я бы тоже так посоветовал. Если вы чувствуете, что метод расширения делает запрос странным, вы можете обойтись без метода расширения. - person Jeroen Huinink; 10.06.2009

Я не думаю, что SqlServer дал вам нулевое исключение. Если это так, то этот код явно не работает через LinqToSql (как вы отметили вопрос).

string.Contains будет переведен в like sql, у которого нет проблем с нулевыми значениями.

person Amy B    schedule 10.06.2009

Убедитесь, что свойства не равны нулю

from a in this._addresses
where (a.Street != null && a.Street.Contains(street)) || 
(a.StreetAdditional != null && a.StreetAdditional.Contains(streetAdditional))
select a).ToList<Address>()

Если нулевая проверка ложна, то второе предложение после && не будет оцениваться.

person Yaakov Ellis    schedule 10.06.2009

Возможно, вы захотите убедиться, что переменные street и streetAdditional не равны нулю. Я только что столкнулся с той же проблемой, и установка для них пустой строки, похоже, решила мою проблему.

street = street ?? "";
streetAdditional = streetAdditional ?? "";
from a in this._addresses
where a.Street.Contains(street) || a.StreetAdditional.Contains(streetAdditional)
select a).ToList<Address>()
person Brian    schedule 29.11.2009

Следует отметить, что значение null должно оцениваться в первую очередь.

where (**a.Street != null** && a.Street.Contains(street)) || (a.StreetAdditional != null && a.StreetAdditional.Contains(streetAdditional))
select a).ToList<Address>

()

person user5636696    schedule 22.02.2016