Если вы хотите выполнить правое внешнее объединение таблиц A и B, просто замените эти таблицы, и вы можете выполнить левое внешнее объединение.
Левое внешнее объединение - это GroupJoin, за которым следует SelectMany. По своему опыту я использую GroupJoin гораздо чаще, чем левое внешнее соединение. Особенно в отношениях «один ко многим».
Например: Предположим, у вас есть таблица школ и таблица студентов. В каждой школе учится ноль или более учеников, каждый ученик учится ровно в одной школе с использованием внешнего ключа SchoolId: прямое отношение «один ко многим».
Дайте мне все школы со всеми своими учениками
var result = dbContext.Schools
.GroupJoin(dbContext.Students, // GroupJoin Schools and Students
school => school.Id, // from every School take the primary key
student => student.SchoolId, // from every Student take the foreign key
(school, studentsOnThisSchool) => new // from every School with all its Students
{ // make one new object
// Select only the School properties I plan to use
Id = schoolId,
Name = school.Name,
OlderStudents = studentsOnThisSchool
.Select(student => new
{
// Select only the Student properties I plan to use:
Id = student.Id,
Name = student.Name,
...
// not needed, I already know the value:
// SchoolId = student.SchoolId,
});
Результатом будет следующая последовательность:
School 1 with Students A, B, C, D.
School 2 with Students E, F,
School 3 without any Students
School 4 with Students G, H, I,
...
Это кажется мне гораздо более полезным, чем результат левого внешнего соединения:
School 1 with Student A,
School 2 with Student E,
School 3 with Null student,
School 1 with Student B,
School 2 with Student F,
School 1 with Student C,
...
Но, эй, это ваш выбор.
У меня есть TblTrade, в котором содержатся сделки. Каждая сделка имеет как минимум свойства Bt, PosGuid и RowType. У меня также есть TblSechedule, который содержит расписания. Каждое расписание имеет как минимум свойства Bt и PosGuid. Дайте мне все сделки с RowType 4 со всеми нулями или более графиками, которые имеют одинаковое значение для PosGuid.
var result = tblTrade
// keep only the trades that have RowType equal to 4:
.Where(trade => trade.RowType == 4)
// do the GroupJoin:
.GroupJoin(tblSchedule,
trade => trade.PosGuid,
schedule => schedule.PosGuid,
(trade, schedulesWithSamePosGuid) => new
{
// Select the trade properties you plan to use:
TradeId = trade.Id,
PosGuid = trade.PosGuid,
...
Schedules = schedulesWithSamePosGuid.Select(schedule => new
{
// Select the schedule properties you plan to use:
Id = schedule.Id,
...
// not needed, you already know the value:
// PosGuid = schedule.PosGuid.
})
.ToList(),
});
Если вы действительно хотите плоское внешнее левое соединение, добавьте SelectMany:
.SelectMany(groupJoinResult.Schedules,
(trade, schedule) => new
{
PosGuid = trade.PosGuid,
// the Trade properties:
Trade = new
{
Id = trade.TradeId,
...
},
Schedule = new
{
Id = schedule.Id,
...
},
});
Если хотите, вы можете создать функцию расширения LeftOuterJoin:
public static class MyQueryableExtensions
{
// version without EqualityComparer:
public static IQueryable<TResult> LeftOuterJoin<T1, T2, TKey, TResult>(
this IQueryable<T1> source1,
IQueryable<T2> source2,
Func<T1, TKey> key1Selector,
Func<T2, TKey> key2Selector,
Func<T1, T2, TResult) resultSelector)
{
return LeftOuterJoin(source1, source2,
key1Selector, key2Selector, resultSelector, null);
}
версия с EqualityComparer:
public static IQueryable<TResult> LeftOuterJoin<T1, T2, TKey, TResult>(
this IQueryable<T1> source1,
IQueryable<T2> source2,
Func<T1, TKey> key1Selector,
Func<T2, TKey> key2Selector,
Func<T1, T2, TResult) resultSelector,
IEqualityComparer<TKey> comparer)
{
if (comparer == null) comparer = EqualityComparer<TKey>.Default;
// GroupJoin followed by SelectMany:
return GroupJoin(source1, source2, key1Selector, key2Selector,
(source1Item1, source2ItemsWithSameKey) => new
{
Source1Item = source1Item,
Source2Items = source2ItemsWithSameKey,
})
.SelectMany(groupJoinResult => groupJoinResult.Source2Items,
(groupJoinResult, source2Item) =>
ResultSelector(groupJoinResult.Source1Item, source2Item));
}
}
Использование:
var result = tblTrade
.Where(trade => trade.RowType == 4)
.LeftOuterJoin(tblSchedule,
trade => trade.PosGuid,
schedule => schedule.PosGuid,
(trade, schedule) => new
{
// Select the trade and Schedule properties that you plan to use
// for example the complete trade and schedule:
Trade = trade,
Schedule = schedule,
// or only some properties:
CommonPosGuid = trade.PosGuid,
Trade = new
{
Id = trade.Id,
...
}
Schedule = new
{
Id = trade.Id,
...
}
})