Перегруппировка результатов левого объединения "многие ко многим" в иерархию в запросе EF Core 2.2 Linq - PullRequest
0 голосов
/ 08 ноября 2019

У меня следующий (упрощенный, но достаточно хороший, чтобы продемонстрировать проблему) запрос:

var schoolsQuery = _dbContext.Set<School>();

var schoolSubjectTeachersQuery = _dbContext.Set<SchoolSubjectTeacher>();
var teacherSubjectsQuery = _dbContext.Set<SubjectTeacher>();
var teachersQuery = _dbContext.Set<Teacher>();
var teacherPersonQuery = _dbContext.Set<PersonInfo>();

// projecting to a simplified, detached viewlist entity to collect minimum required fields only
// and to generate an optimal query with left joins

// many-to-many joins: schools -> school teacher subjects -> teacher subjects -> teachers -> teacher info to finally get schools with all unique teachers inside
var projected = (from s in schoolsQuery
                join sst in schoolSubjectTeachersQuery on s.Id equals sst.SchoolId into schoolSubjectTeachers
                    from sstj in schoolSubjectTeachers.DefaultIfEmpty()
                join ts in teacherSubjectsQuery on sstj.TeacherSubjectId equals ts.Id into teacherSubjects
                    from tsj in teacherSubjects.DefaultIfEmpty()
                join t in teachersQuery on tsj.TeacherId equals t.Id into teachers
                    from tj in teachers.DefaultIfEmpty()
                join tp in teacherPersonQuery on tj.PersonId equals tp.Id into teacherPersons
                    from tpj in teacherPersons.DefaultIfEmpty()

                // ignore deleted teachers and school-teachersubject and teacher-subject links that are no longer active
                where (sstj == null || !sstj.Isdeleted) && 
                      (tsj == null || !tsj.Isdeleted) &&
                      (tj == null || !tj.Isdeleted)

                select new SimpleViewOfSchoolWithActiveTeachers
                {
                    Id = s.Id,
                    SchoolName = s.SchoolName,
                    SchoolAddress = s.SchoolAddress,

                    // hacky - storing single teacher into the flat list
                    // TODO: redesign to make EF intelligently rearrange the flat list into hierarchy
                    // with all schools and nested teachers, if any

                    Teachers = tpj == null ? null : new List<SimpleViewOfActiveTeacher> { new ViewOfActiveTeacher {
                         Id = tj.Id, // id of the teacher record
                         PersonId = tpj.PersonId, // data from the person info record of the teacher
                         PersonFullName = tpj.PersonFullName // data from the person info record of the teacher
                    } }
                });

var results = projected.ToList();

// got a flat list here with a school attached to every left-joined teacher

В общем, это работает - я получаю список всех школ и их учителей, но есть двапроблемы:

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

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

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

Однако я надеялся, что есть более элегантное решение.

Есть ли что-то, что использует встроенные механизмы EntityFramework или Linq вместо ручной итерации и исправления иерархии набора результатов?

...