Отношения Linq и ключей, допускающих значение NULL, влияющие на операцию UNION

Вот пример:

Допустим, у меня есть 3 таблицы: страны, люди и города. Записи о городах имеют необнуляемое поле внешнего ключа, идентифицирующее страну. В записях людей есть поле внешнего ключа nullable, идентифицирующее страну — они могут быть из восточноевропейской страны, которой больше не существует.

Я хочу создать комбинированный список стран из списка людей и списка городов:

var people = dbContext.People.Where(...);
var cities = dbContext.Cities.Where(...);

var countries = cities.Select(c=>c.Country);
countries = countries.Union(people.Select(p=>p.Country));

Проблема исходит из этой последней строки. Поскольку не все записи людей имеют совпадающую запись страны, LINQ (правильно) создает запрос, который гарантирует, что строка будет заполнена нулями для каждого человека без гражданства. С отладчиком кажется, что это делается путем создания фиктивного столбца с вызовом "[test]"

SELECT [t2].[test], [t2].[CountryID], [t2].[Name]
FROM [dbo].[People] AS [t0]
LEFT OUTER JOIN (
    SELECT 1 AS [test], [t1].[CountryID], [t1].[Name]
    FROM [dbo].[Countries] AS [t1]
    ) AS [t2] ON [t2].[CountryID] = [t0].[CountryID]

Хотя этот дополнительный столбец [тест] молча удаляется (результат идентифицируется как IQueryable) на стороне кода, на стороне SQL он определенно присутствует и приводит к отклонению запроса, когда я объединяю его с обычным выбором страны. утверждение.

В последнем случае я не хочу и не нуждаюсь в дополнительных фиктивных строках - в полную программу я уже включил people.Where(p=>p.CountryID != null).Select(p=>p.Country), а также попробовал p=>Country != null.

Однако Linq не распознает, что это предотвратит нулевые строки, и поэтому по-прежнему вставляет тестовый столбец. поскольку тестовый столбец невидим, у меня нет очевидного способа «удалить» его из того, что в противном случае сообщается как объект IQueryable. Конечным результатом является ошибка времени выполнения из-за того, что моя конструкция UNION имеет неравное количество столбцов.

Как я могу принудительно включить INNER JOIN в моем обнуляемом отношении или иным образом заставить объединение работать так, как я хочу, исключив невидимый тестовый столбец?


person David    schedule 01.09.2009    source источник


Ответы (1)


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

var people = dbContext.People.Where(...);
var cities = dbContext.Cities.Where(...);

var countryIds =
  cities
    .Select(c => c.CountryID)
  .Union(people
    .Select(p => p.CountryID)
    .Where(cID => cID.HasValue)
    .Select(cID => cID.Value));

var countries = dbContext.Countries
  .Where(c => countryIds.Contains(c.CountryID));
person Amy B    schedule 01.09.2009