Запрос внешнего соединения с использованием LINQ to Entities

В моей компании от 0 до n отделов, от 0 до n отделений в 1 отделе и от 0 до n сотрудников в 1 отделении. Теперь мне нужен запрос с использованием linq для отображения среднего возраста сотрудников по департаментам, если в отделе нет никого, то средний по умолчанию 0. Код ниже:

    DataContext ctx = new DataContext();

    var q0 = from d in ctx.Departments
             join o in ctx.Offices on d.Id equals o.DepartmentId
             join e in ctx.Employees on o.Id equals e.OfficeId
             group e by d into de
             select new {
                DepartmentId = de.Key.Id,
                AverageAge = de.Count() == 0 ? 0 : de.Average(e => e.Age),
             };


    var q1 = from d in ctx.Departments
             join de in q0 on d.Id equals de.DepartmentId into des
             from de in des.DefaultIfEmpty()
             select new
             {
                 DepartmentName = d.Name,
                 AverageAge = de == null ? 0 : de.AverageAge
             };

    var result = q1.ToList();
    foreach (var item in result)
    {
        Console.WriteLine("{0}-{1}", item.DepartmentName, item.AverageAge);
    }
    ctx.Dispose();

Но как объединить q0 и q1 в один запрос?

2 ответа

Решение
    were you meaning something along the lines of:

var newQ2 = from d in ctx.Departments
                 outer left join o in ctx.Offices on d.Id equals o.DepartmentId
                 outer left join e in ctx.Employees on o.Id equals e.OfficeId
                 group e by d into de
                 select new {
                    DepartmentId = de.Key.Id,
                    AverageAge = de.Count() == 0 ? 0 : de.Average(e => e.Age),
                 };

изменился на:

var newQ2 = from d in ctx.Departments
                     join o in ctx.Offices on d.Id equals o.DepartmentId
                     join e in ctx.Employees on o.Id equals e.OfficeId
                     group e by d into de.DefaultIfEmpty()
                     select new {
                        DepartmentId = de.Key.Id,
                        DepartdentName = select d.Name from d where d.id = de.Key.Id,
                        AverageAge = de.Count() == 0 ? 0 : de.Average(e => e.Age),
                     };

Приложение: Я бы использовал суб-выбор для подбора дополнительного имени, не зная вашего макета БД, который я импровизировал из вашего кода, но вы могли бы сделать его более эффективным и иметь многокомпонентное объединение на основе также суб-выбора. Извините, я не могу проверить этот код на работе, я могу довольно хорошо аппроксимировать, но мне нужна дополнительная информация о том, где находятся названия ваших отделов, если вам нужен более подробный ответ:) Я изменил внешние левые соединения обратно на объединения, извините Я забыл в C# с Linq вы можете использовать DefaultIfEmpty(), чтобы вызвать поведение внешнего левого соединения в коде.

Внешнее левое соединение вернет нули, где нет соответствующих значений, но разрешит возвраты для любых частей, которые имеют соответствующее значение. Однако Join не вернет пустых записей, что, как я подозреваю, вызвало два запроса?

Единственное предостережение в отношении запроса, который я представил, заключается в том, что вам нужно будет заполнить любые значения, которые вам требуются, прежде чем использовать их, если они являются нулевыми, например, для DepartmentId потребуется некоторая логика для его заполнения в случае, если DE равно нулю.

Спасибо всем , У меня есть ответ:

        var q1 = 
                 from d in ctx.Departments 
                 from o in ctx.Offices.Where(o => o.DepartmentId == d.Id).DefaultIfEmpty()
                 from e in ctx.Employees.Where(e =>  e.OfficeId == o.Id).DefaultIfEmpty()
                 group e by d into de
                 select new {
                    DepartmentName = de.Key.Name,
                    AverageAge = de.Average(e => e == null ? 0 : e.Age),
                 };
Другие вопросы по тегам