Запрос внешнего соединения с использованием 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),
};