Я думаю, что родители и ребенок не очень хорошо подходят как отдельные сущности.Ребенок всегда может быть также родителем, и обычно у него есть два родителя (отец и мать), так что это не самый простой контекст.Но я предполагаю, что у вас просто простое отношение 1: n, как в следующей модели «ведущий-ведомый», которую я использовал.
Вам нужно сделать левое внешнее соединение (этот ответпривело меня на правильный путь).Такое объединение немного сложнее, но вот код
var query = from m in ctx.Masters
join s in ctx.Slaves
on m.MasterId equals s.MasterId into masterSlaves
from ms in masterSlaves.Where(x => x.Age > 5).DefaultIfEmpty()
select new {
Master = m,
Slave = ms
};
foreach (var item in query) {
if (item.Slave == null) Console.WriteLine("{0} owns nobody.", item.Master.Name);
else Console.WriteLine("{0} owns {1} at age {2}.", item.Master.Name, item.Slave.Name, item.Slave.Age);
}
Это будет переводиться в следующий оператор SQL с EF 4.1
SELECT
[Extent1].[MasterId] AS [MasterId],
[Extent1].[Name] AS [Name],
[Extent2].[SlaveId] AS [SlaveId],
[Extent2].[MasterId] AS [MasterId1],
[Extent2].[Name] AS [Name1],
[Extent2].[Age] AS [Age]
FROM [dbo].[Master] AS [Extent1]
LEFT OUTER JOIN [dbo].[Slave] AS [Extent2]
ON ([Extent1].[MasterId] = [Extent2].[MasterId]) AND ([Extent2].[Age] > 5)
Обратите внимание, что важно выполнитьдополнительное условие where на возраст объединенной коллекции, а не между from и select.
EDIT:
Если вы хотите получить иерархический результат, вы можете преобразовать плоский список, выполнив группировку:
var hierarchical = from line in query
group line by line.Master into grouped
select new { Master = grouped.Key, Slaves = grouped.Select(x => x.Slave).Where(x => x != null) };
foreach (var elem in hierarchical) {
Master master = elem.Master;
Console.WriteLine("{0}:", master.Name);
foreach (var s in elem.Slaves) // note that it says elem.Slaves not master.Slaves here!
Console.WriteLine("{0} at {1}", s.Name, s.Age);
}
Обратите внимание, что я использовал анонимный тип для хранения иерархического результата.Конечно, вы можете создать также определенный тип, подобный этому
class FilteredResult {
public Master Master { get; set; }
public IEnumerable<Slave> Slaves { get; set; }
}
, а затем спроецировать группу на экземпляры этого класса.Это облегчает задачу, если вам нужно передать эти результаты другим методам.