Вот запрос для получения плоского результирующего набора с правильными левыми объединениями.
var query = from cell in Cell
join container in Container.Where (row => row.SerialNumber == "1102141") on cell.CellID equals container.CellID
into containers
from container2 in containers.DefaultIfEmpty()
join printer in Printer.Where (row => row.Name == "PG10RelWarrPrt3") on cell.CellID equals printer.CellID
into printers
from printer2 in printers.DefaultIfEmpty()
select new { Cell = cell, Container = container2, Printer = printer2 };
Вам придется постобработать результаты локально, чтобы получить желаемую иерархическую форму.
Если вы напишите этот код постобработки, вы поймете, почему linq to sql не обрабатывает для вас несколько собраний одного уровня.
Чтобы сделать это более понятным, предположим, что у вас есть 3 коллекции братьев и сестер.
Если бы все три коллекции одноуровневых элементов были пусты для какой-либо родительской записи, у вас была бы только родительская запись 1 раз с кучей нулей.
Если бы во всех трех коллекциях братьев и сестер было 100 записей для какой-либо родительской записи, у вас было бы 1 миллион строк , каждая с копией родительской записи. В результате каждая дочерняя запись будет продублирована 10000 раз.
Всегда важно помнить, что с любым ORM он генерирует sql и возвращает плоские результирующие наборы, независимо от того, какой результат иерархической формы он в конечном итоге вам преподнесет.