Интересно, что после прочтения вашего поста и небольшого тестирования я понял, что то, что вы делаете на самом деле, мне кажется, работает нормально, учитывая, что проекционная часть, которую вы показываете как многоточие в обоих ваших запросах, совпадает. Видите ли, LINQ to SQL, по-видимому, создает базовую проекцию для команды выбора SQL на основе операторов присваивания свойств, а не фактического материализуемого типа, при условии, что обе стороны имеют одинаковое число, тип и порядок (не уверен об этом) из назначений членов запрос UNION должен быть действительным.
Мое решение, с которым я работал, - это создать свойство в моем классе DataContext, которое будет работать так же, как SQL-представление, в котором оно позволяет мне написать запрос (в моем случае объединение между двумя различными таблицами), а затем используйте этот запрос, как будто он сам по себе как таблица при составлении операторов выбора только для чтения.
public partial class MyDataContext
{
public IQueryable<MyView> MyView
{
get
{
var query1 =
from a in TableA
let default_ColumnFromB = (string)null
select new MyView()
{
ColumnFromA = a.ColumnFromA,
ColumnFromB = default_ColumnFromB,
ColumnSharedByAAndB = a.ColumnSharedByAAndB,
};
var query2 =
from a in TableB
let default_ColumnFromA = (decimal?)null
select new MyView()
{
ColumnFromA = default_ColumnFromA,
ColumnFromB = b.ColumnFromB,
ColumnSharedByAAndB = b.ColumnSharedByAAndB,
};
return query1.Union(query2);
}
}
}
public class MyView
{
public decimal? ColumnFromA { get; set; }
public string ColumnFromB { get; set; }
public int ColumnSharedByAAndB { get; set; }
}
Обратите внимание на две ключевые вещи:
Прежде всего, проекция, сформированная запросами, составляющими обе половины Союза, имеет одинаковое количество, тип и порядок столбцов. Теперь LINQ может потребовать, чтобы порядок был таким же (не уверен в этом), но это определенно верно, что SQL делает для UNION, и мы можем быть уверены, что LINQ потребует по крайней мере того же типа и числа столбцов и этих «столбцов» известны члену назначения , а не из свойств типа, который вы создаете в своей проекции.
Во-вторых, LINQ в настоящее время не позволяет использовать несколько констант в проекциях для запросов, которые формулируют Concat или Union, и, насколько я понимаю, это происходит главным образом потому, что эти два отдельных запроса оптимизируются отдельно перед обработкой операции Union. Обычно LINQ to SQL достаточно умен, чтобы понять, что если у вас есть постоянное значение, которое используется только в проекции, то зачем отправлять его в SQL, просто чтобы оно вернулось таким, каким оно было, вместо того, чтобы прикреплять его как пост? процесс после того, как необработанные данные возвращаются с SQL Server. К сожалению, проблема здесь в том, что это тот случай, когда LINQ to SQL является умным для его же блага, поскольку он оптимизирует каждый отдельный запрос слишком рано в процессе. Я нашел способ обойти это, используя ключевое слово let , чтобы сформировать переменную диапазона для каждого значения в проекции, которое будет реализовано путем получения его значения из константы. Каким-то образом это заставляет LINQ to SQL переносить эти константы в фактическую команду SQL, которая сохраняет все ожидаемые столбцы в результирующем UNION. Подробнее об этой технике можно узнать здесь .
Используя эту технику, по крайней мере, у меня есть что-то многократно используемое, так что независимо от того, насколько сложным или уродливым может быть настоящий Union, особенно с переменными диапазона, в ваших конечных запросах вы можете записывать запросы в эти псевдо-представления, такие как MyView и deal со сложностью внизу.