2010-11-24 3 views
0

Немного фона по запросу ниже. Ячейка имеет контейнер 1: M и контейнер 1: M с принтером. Я хочу получить запрос, который будет извлекать все ячейки и связанные с ними контейнеры, если они существуют, и связанные с ними принтеры, если они существуют. По сути, я хочу сделать левое внешнее соединение на обеих таблицах. Вот мой запрос:Как сделать несколько левых внешних соединений в запросе Linq?

var query = from cell in Cell 
    join container in Container.Where (row => row.SerialNumber == "1102141") on cell.CellID equals container.CellID 
    into containers 

    join printer in Printer.Where (row => row.Name == "PG10RelWarrPrt3") on cell.CellID equals printer.CellID 
    into printers 

    select new { Cell = cell, Containers = containers, Printers = printers }; 

query.Dump(); 

Этот запрос работает, но не эффективен. Он выполняет левое внешнее соединение в контейнере, но для каждой ячейки он выполняет отдельный запрос для извлечения любых строк принтера вместо того, чтобы выполнять левое внешнее соединение на принтере.

Как я могу изменить это так, чтобы он также выполнял левое внешнее соединение на столе принтера? BTW, мне нужен иерархический набор результатов. IOW, каждая ячейка должна иметь список контейнеров и список принтеров. Разумеется, каждый из них будет пустым, если для ячейки не существует.

+1

http://stackoverflow.com/questions/267488/linq-to-sql-multiple-left-outer-joins – diceguyd30 2010-11-24 13:23:21

+0

@ diceguyd30 - Я видел это, прежде чем отправил свой вопрос. Это не решает мою проблему. Обратите внимание, что я утверждаю, что хочу получить иерархический результирующий набор, а не плоский. DefaultIfEmpty() для плоских наборов результатов. – 2010-11-24 13:28:12

ответ

2

Вот запрос, чтобы получить плоский набор результатов с правильным левым соединением.

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 не обрабатывает несколько коллекций sibling для вас.


Чтобы сделать это более понятным, предположим, что у вас было 3 коллекции братьев и сестер.

Если все три коллекции сестер были пустыми для какой-либо родительской записи, у вас будет только родительская запись 1 раз с пучком нулей.

Если у всех трех коллекций братьев было 100 записей для какой-либо родительской записи, у вас было бы 1 миллион строк, каждая из которых имела бы копию родительской записи. Каждая детская запись будет дублироваться в 10 000 раз.

Всегда важно помнить, что любой ORM, который он генерирует sql, и возвращает плоские результирующие наборы, независимо от того, какой результат иерархической формы он в конечном итоге представляет вам.

Смежные вопросы