Linq Left Join: Можно ли оптимизировать linq запрос?

246
08 декабря 2016, 22:43

Мне необходимо показать пользователю представление, информация для отображении находится в разных таблицах.

Для упрощения я получаю данные несколькими запросами, после этого я склеиваю все эти данные при помощи левых соединений.

linq запрос выглядит так:

var operations = _context.Set<Operation>()
                    .Include(x=>x.Product)
                    .ToList();
var timeWorks = _context.Set<OperationItem>()
                    .Where()
                    .ToList();
var attachments = _context.Set<OperationItem>()
                    .Where()
                    .ToList();
var result = operations
                 .GroupJoin(attachments, o=>o.Id, i=>i.OperationId, (l,r)=> new {Operation = l, Attachment = r})
                 .SelectMany(x=>x.Attachment.DefaultIfEmpty(), (l,r)=>new {Operation = l.Operation, Attachment = r})
                 .GroupJoin(timeWorks, o=>o.Operation.OperationId, i=>i.OperationId, (l,r)=> new {Operation = l.Operation, Attachment = l.Attaqchment, TimeWork = r.Sum(_=>_.TimeWork)})
                 .Select(x=> new OperationList
                 {
                     //Собираем окончательное представление
                 })
                 .ToList();

Все работает так как необходимо, но мне не нравится что для каждого левого соединения приходится прокидывать результат предыдущего соединения:

new {Operation = l.Operation, Attachment = l.Attaqchment, TimeWork = r.Sum(_=>_.TimeWork)}

Подскажите может я что то делаю не так и можно это сделать проще?

Answer 1

Для исключения "прокидывания" можно воспользоваться встроенной формой linq - в таком случае компилятор позаботится о прокидывании сам:

var result = from operation in operations
             join attachment in attachments on operation.Id equals attachment.OperationId into attachmentsgroup
             from attachment in attachmentsgroup.DefaultIfEmpty()
             join timeWork in timeWorks on operation.Id equals timeWork.OperationId into timeWorksgroup
             let timeWork = timeWorksgroup.Sum(_ => _.TimeWork)
             select new OperationList {
               // ...
             };

Но, вообще говоря, left join через group join - это трюк, который пригоден для применения только в запросах к базе, где left join является "родным" оператором.

Для запросов к объектам все делается намного проще!

var operations = _context.Set<Operation>()
                    .Include(x=>x.Product)
                    .AsEnumerable();
var timeWorks = _context.Set<OperationItem>()
                    .Where()
                    .ToLookup(x => x.OperationId);
var attachments = _context.Set<OperationItem>()
                    .Where()
                    .ToLookup(x => x.OperationId);
var result = from operation in operations
             from attachment in attachments[operation.Id].DefaultIfEmpty()
             let timeWork = timeWorks[operation.Id].Sum(_ => _.TimeWork)
             select new OperationList {
               // ...
             };
READ ALSO
C# XNA как узнать разрешение экрана/окна

C# XNA как узнать разрешение экрана/окна

Нужно узнать текущие разрешение экрана(для полно экранного режима) и отдельно нужно узнать разрешение окна(оконный режим) Есть какие либо...

440
Вызов метода класса по имени

Вызов метода класса по имени

Необходимо вызывать методы класса по имени (те

219
ContextMenuStrip, как отловить закрытие

ContextMenuStrip, как отловить закрытие

Вот так создаю меню правой кнопки мыши над DataGridView :

197
Несуществующие баги в *.cshtml

Несуществующие баги в *.cshtml

Доброго времени суток!Имеется проект asp

246