Подтвердить что ты не робот

LINQ to Entities, генерирующий неверный SQL

Я фильтрую IQueryable для возврата всех объектов, у которых есть поле UserId (nullable int), установленное в null. Запрос генерирует неправильный SQL и, таким образом, сбой - это утверждение следующим образом -

var filtered = certificates.Where(c => !c.UserId.HasValue).Select(c => c.SubjectName);

а сгенерированный SQL -

SELECT 
CAST(NULL AS varchar(1)) AS [C1], 
CAST(NULL AS int) AS [C2], 
CAST(NULL AS datetime2) AS [C3], 
CAST(NULL AS datetime2) AS [C4], 
CAST(NULL AS bit) AS [C5], 
CAST(NULL AS datetime2) AS [C6], 
CAST(NULL AS int) AS [C7]
FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
WHERE 1 = 0

Любая идея WTF продолжается? Идея проста: я просто хочу вернуть все строки, где поле UserId ложно. UserId имеет значение NULL, и запрашиваемая таблица имеет три строки, которые соответствуют описанному условию, однако запрос LINQ возвращает 0.

Спасибо!

4b9b3361

Ответ 1

Это тот тип запроса, который генерирует EF, когда он точно знает, что запрос не вернет никаких результатов. Такой запрос минимизирует обработку базы данных.

Как EF может быть так уверен? Это может быть только тогда, когда для всего, что он знает, UserId в базе данных не имеет значения NULL. Это, в свою очередь, может быть только тогда, когда имеется также User ссылка в Certificate (класс POCO), которая отображается по мере необходимости. Найдите что-то вроде

HasRequired(t => t.User).WithMany(t => t.Certificates)

в EntityTypeConfiguration<Certificate> или в переопределении OnModelCreating в вашем DbContext. (Вначале кода можно получить требуемую ссылку, а сопроводительное свойство примитивного идентификатора - тип с нулевым значением. В файле edmx это не проверяется).

Итак, я думаю, что вам нужно сопоставить User как необязательный, если в базе данных внешний ключ имеет значение NULL.

Ответ 2

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

  var filtered = certificates.Where(c => c.UserId == null).Select(c => c.SubjectName);

Ответ 3

Я считаю, что причина, по которой он не работает для вас, заключается в том, что c.UserId имеет значение, оно равно null. Вместо этого вы должны сравнить его с нулевым:

var filtered = certificates.Where(c => c.UserId == null).Select(c => c.SubjectName);

edit: Случайно был неправильный оператор if.