Нулевое объединение не работает в запросе LINQ

Возьми это:

int? item1 = null;
int? item2 = null;

someObjectList.Where(x => x.SomeItem1 == (item1 ?? x.SomeItem1)
                       && x.SomeItem2 == (item2 ?? x.SomeItem2) 
                    );

Где someObjectList не пусто, а SomeItem1 и SomeItem2 равно null во всех объектах в списке.

Почему он ничего не возвращает?

ИЗМЕНИТЬ:

Мой код:

public void GetPlacementsByMaterial(long clientMaterialID)
{
    ClientMaterial clientMaterial = ((ApplicationEntityModel)NavigationItem.ObjectContext).ClientMaterial.FirstOrDefault(x => x.ClientMaterialID == clientMaterialID);

    var list = GetPlacementList(supplier, mediaSpace);

    PlacementsList = list.Where(x => x.MediaCategoryFormatID == (clientMaterial.MediaCategoryFormatID ?? x.MediaCategoryFormatID)
                                                && x.MediaCategorySizeID == (clientMaterial.MediaCategorySizeID ?? x.MediaCategorySizeID) 
                             );
}

Все идентификаторы Nullable<long>.

ИЗМЕНИТЬ:

Профилировщик SQL:

SELECT *
  FROM [dbo].[CampaignSchedulePlacements] AS [Extent5]
WHERE ([Extent5].[MediaCategoryFormatID] = [Extent5].[MediaCategoryFormatID]) AND ([Extent5].[MediaCategorySizeID] = [Extent5].[MediaCategorySizeID])

Примечание: очищен файл `SQL.


person Willem    schedule 21.07.2012    source источник
comment
Пожалуйста, опубликуйте полный пример, который воспроизводит проблему.   -  person CodesInChaos    schedule 21.07.2012
comment
Он отлично работает для меня. Какой тип SomeItem1? У него есть перегруженный оператор ==?   -  person Ry-♦    schedule 21.07.2012
comment
Какой тип list? Используете ли вы Linq-To-Objects или что-то IQueryable?   -  person CodesInChaos    schedule 21.07.2012
comment
@CodesInChaos Использование Linq-to-entities и все основные запросы. Ничего фантастического. Все объекты имеют тип EntityObject. Я просто не могу понять это...   -  person Willem    schedule 21.07.2012
comment
Вы используете Linq to Entities. Посмотрите на фактический SQL, сгенерированный с помощью отладчика (например, в Intellitrace).   -  person Kris Vandermotten    schedule 21.07.2012
comment
что на самом деле в таблице? как сказал Крис, если вы сравниваете NULL с NULL, он будет оценен как false и не вернет запись, поэтому любая запись с NULL MediaCategoryFormatID или NULL MediaCategorySizeID не будет возвращена.   -  person Dave Cousineau    schedule 21.07.2012
comment
Для полноты NULL = NULL оценивается как неизвестное, а не как ложное. Это важно, потому что NOT(NULL = NULL) не (неизвестно) (это еще неизвестно), не не (ложно) (это правда)   -  person    schedule 21.07.2012


Ответы (1)


В SQL NULL не равно NULL.

Вы можете интерпретировать NULL как означающее: «значение есть, но я не знаю, что это такое». Итак, если вы сравниваете два значения NULL, вы на самом деле спрашиваете: «Равно ли первое неизвестное значение второму неизвестному значению?» Конечно, нет причин предполагать, что это так, поэтому SQL скажет «нет».

Я предполагаю, что это вызывает вашу проблему. Вы можете убедиться в этом, посмотрев фактически созданный SQL. Если он использует оператор SQL =, это действительно проблема. Вы можете убедиться в этом, запустив SQL в инструменте базы данных, таком как SQL Management Studio, если вы используете SQL Server.

ОБНОВИТЬ:

Состояние

([Extent5].[MediaCategoryFormatID] = [Extent5].[MediaCategoryFormatID]) 

действительно вернет false, если [Extent5].[MediaCategoryFormatID] имеет значение NULL.

Это отвечает на вопрос «Почему он ничего не возвращает?»

Однако на ум приходит другой вопрос: зачем инфраструктуре сущностей генерировать этот SQL из этого запроса linq?

Я боюсь, что linq to entity точно не известен качеством генерации SQL, и этот случай, похоже, подтверждает это. Вы можете рассмотреть Linq to SQL. Даже если в долгосрочной перспективе это кажется тупиковым путем, текущая реализация намного лучше, чем привязка к сущностям.

В любом случае, вы пробовали что-то вроде

someObjectList.Where(x => 
    !item1.hasValue || 
    x.SomeItem1.HasValue && x.SomeItem1.Value == item1.Value)

Не забудьте убедиться, что и в профилировщике linq to entity тоже может все испортить.

person Kris Vandermotten    schedule 21.07.2012
comment
Пожалуйста, смотрите мое обновление. Я запускаю его на SQL Profiler. Любые другие идеи? - person Willem; 21.07.2012
comment
Спасибо Крис. Сортировка. Это было NULL по обе стороны от ==. - person Willem; 21.07.2012
comment
@Willem и Kris: на самом деле это старая ошибка в LINQ to Entities: stackoverflow.com/questions/682429/ null == null это true в .NET, поэтому его нельзя переводить напрямую в NULL = NULL в SQL, который не true. Это было исправлено для .NET 4.5., поэтому вам больше не нужны обходные пути, описанные выше и в ответах на связанный вопрос, в .NET 4.5. - person Slauma; 21.07.2012
comment
@Slauma Спасибо за ссылку. +1 - person Willem; 21.07.2012