Как выполнить обход дерева в глубину без повторений?

Собственно, есть таблица

GroupClasses (GroupClass)
...
Guid ParentGroupClassId?
GroupClass? ParentGroupClass
IEnumerable Parents


Собираю простой запрос -
var groupClasses = await _dbContext.GroupClasses.Include(x => x.ParentGroupClass)
                                                            .Where(x => x.GroupId == groupId)
                                                            .ToListAsync();


На выходе вот такое чудо

spoiler
{
  "groupClasses": [
    {
      "id": "085f819e-9c5b-4ddc-a491-e15d5c4e134b",
      "parentGroupClass": null,
      "periodId": 1,
      "quarter": 0,
      "day": 0,
      "auditoryId": 1,
      "lecturerId": 23,
      "lessonId": 1,
      "groupId": 1
    },
    {
      "id": "cc3f4a1e-4503-49cd-81a9-31f2344a014a",
      "parentGroupClass": null,
      "periodId": 1,
      "quarter": 0,
      "day": 0,
      "auditoryId": 1,
      "lecturerId": 23,
      "lessonId": 1,
      "groupId": 1
    },
    {
      "id": "e29e60bc-7661-47c5-bd2a-8d6a04d4ef69",
      "parentGroupClass": null,
      "periodId": 1,
      "quarter": 0,
      "day": 0,
      "auditoryId": 1,
      "lecturerId": 23,
      "lessonId": 1,
      "groupId": 1
    },
    {
      "id": "39ae3afd-2f22-482c-9cb9-17166d51e802",
      "parentGroupClass": null,
      "periodId": 1,
      "quarter": 0,
      "day": 0,
      "auditoryId": 1,
      "lecturerId": 23,
      "lessonId": 1,
      "groupId": 1
    },
    {
      "id": "d3e8cf58-26f9-42be-b4c8-90ead84780af",
      "parentGroupClass": null,
      "periodId": 1,
      "quarter": 0,
      "day": 0,
      "auditoryId": 1,
      "lecturerId": 23,
      "lessonId": 1,
      "groupId": 1
    },
    {
      "id": "ad794686-8760-4116-87a4-df62e95b178b",
      "parentGroupClass": null,
      "periodId": 1,
      "quarter": 0,
      "day": 0,
      "auditoryId": 1,
      "lecturerId": 23,
      "lessonId": 1,
      "groupId": 1
    },
    {
      "id": "4d096187-d0a8-47f7-938a-ca8825acc3b6",
      "parentGroupClass": {
        "id": "ad794686-8760-4116-87a4-df62e95b178b",
        "parentGroupClass": null,
        "periodId": 1,
        "quarter": 0,
        "day": 0,
        "auditoryId": 1,
        "lecturerId": 23,
        "lessonId": 1,
        "groupId": 1
      },
      "periodId": 1,
      "quarter": 0,
      "day": 0,
      "auditoryId": 1,
      "lecturerId": 23,
      "lessonId": 1,
      "groupId": 1
    },
    {
      "id": "9f77beab-956b-4cf9-bf5f-682a57edab3e",
      "parentGroupClass": {
        "id": "4d096187-d0a8-47f7-938a-ca8825acc3b6",
        "parentGroupClass": {
          "id": "ad794686-8760-4116-87a4-df62e95b178b",
          "parentGroupClass": null,
          "periodId": 1,
          "quarter": 0,
          "day": 0,
          "auditoryId": 1,
          "lecturerId": 23,
          "lessonId": 1,
          "groupId": 1
        },
        "periodId": 1,
        "quarter": 0,
        "day": 0,
        "auditoryId": 1,
        "lecturerId": 23,
        "lessonId": 1,
        "groupId": 1
      },
      "periodId": 1,
      "quarter": 0,
      "day": 0,
      "auditoryId": 1,
      "lecturerId": 23,
      "lessonId": 1,
      "groupId": 1
    },
    {
      "id": "c8a1eb96-806d-4ead-86f7-8b86574443d0",
      "parentGroupClass": {
        "id": "9f77beab-956b-4cf9-bf5f-682a57edab3e",
        "parentGroupClass": {
          "id": "4d096187-d0a8-47f7-938a-ca8825acc3b6",
          "parentGroupClass": {
            "id": "ad794686-8760-4116-87a4-df62e95b178b",
            "parentGroupClass": null,
            "periodId": 1,
            "quarter": 0,
            "day": 0,
            "auditoryId": 1,
            "lecturerId": 23,
            "lessonId": 1,
            "groupId": 1
          },
          "periodId": 1,
          "quarter": 0,
          "day": 0,
          "auditoryId": 1,
          "lecturerId": 23,
          "lessonId": 1,
          "groupId": 1
        },
        "periodId": 1,
        "quarter": 0,
        "day": 0,
        "auditoryId": 1,
        "lecturerId": 23,
        "lessonId": 1,
        "groupId": 1
      },
      "periodId": 1,
      "quarter": 0,
      "day": 0,
      "auditoryId": 1,
      "lecturerId": 23,
      "lessonId": 1,
      "groupId": 1
    },
    {
      "id": "4fe7cee7-965f-4794-bbbe-b58659d09099",
      "parentGroupClass": {
        "id": "e29e60bc-7661-47c5-bd2a-8d6a04d4ef69",
        "parentGroupClass": null,
        "periodId": 1,
        "quarter": 0,
        "day": 0,
        "auditoryId": 1,
        "lecturerId": 23,
        "lessonId": 1,
        "groupId": 1
      },
      "periodId": 1,
      "quarter": 0,
      "day": 0,
      "auditoryId": 1,
      "lecturerId": 23,
      "lessonId": 1,
      "groupId": 1
    }
  ]
}


Поскольку EntityFramework обрабатывает каждую сущность из строки - то вот и дубликация данных. При большем количестве... Тут просадки будут такие, что офигеть можно. Ибо перебор всех вариантов.

В общем на sql я бы написал что-то подобное. Отсортировал бы по depth и взял из бы максимальный относительно группы по запросу.
63cc63911afe3537412654.png

А собственно мой вопрос в том, как это можно реализовать (желательно эффективным образом) на EF.

P.S - это таблица с расписанием предметов. Для каждого корня - есть свои экземпляры (генерятся сервисом каждый день). Т.е тут один-ко-многим. Но проблема в том, что у каждого экземпляра (т.е у которого parentGroupClassId != null) могут быть и свои потомки. В таком случае эта запись считается за "замену" и т.д пока не найдется самая "свежая" версия.

Поскольку есть доменное условие - где depth = 1.
То, я мог бы написать что-то подобное
var dailyGroupClasses = await _dbContext.GroupClasses.Include(x => x.ParentGroupClass).Where(x => x.ParentGroupClass.ParentGroupClassId == null).ToListAsync();
foreach(var gc in dailyGroupClasses) {
     var versions = await _dbContext.GroupClasses.Include(x => x.ParentGroupClass).Where(x => x.ParentGroupClassId == gc.Id).ToListAsync();
    ... а вот что дальше я хз.
} 
}


Я прекрасно понимаю, что есть такая штука как "Created", но все-же интересно как это можно сделать более... универсальным.
  • Вопрос задан
  • 79 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы