Гость
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / Как динамически загружать коллекций сущностей Entity Framework / 19 сообщений из 19, страница 1 из 1
17.08.2021, 17:15
    #40091295
Vlad__i__mir
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
Здравствуйте!

Приложение ASP NET Core 3.1, использую EF Core 3.1.13.

Есть класс сущности БД, объект которого хранит коллекцию объектов этого же класса подчиненные ему. В свою очередь объекты, которые он хранит у себя в коллекции, аналогично могут иметь коллекции с другими объектами подчиненные им этого же класса:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
[Table("groupu")]
    public partial class Groupu
    {
        public Groupu()
        {
            Groupsusers = new HashSet<Groupsusers>();
            InverseGroupParents = new HashSet<Groupu>();
        }

        [Key]
        [Column("Id_Group")]
        public int IdGroup { get; set; }
        [DisplayName("Группа")]
        [Column(TypeName = "varchar(256)")]
        public string Name { get; set; }
        
        [DisplayName("Уровень группы")]
        [Column("Level")]
        public int? Level { get; set; }
        [DisplayName("Подчиняется")]
        [Column("Group_Parents_id")]
        public int? GroupParentsId { get; set; }
       
        [DisplayName("Подчиняется")]
        [ForeignKey(nameof(GroupParentsId))]
        [InverseProperty(nameof(Groupu.InverseGroupParents))]
        public virtual Groupu GroupParents { get; set; }
                    
        [InverseProperty(nameof(Groupu.GroupParents))]
        public virtual ICollection<Groupu> InverseGroupParents { get; set; }
    }



Задача обойти всех потомков текущей группы до самого низа. Я это делаю с помощью обхода графа в ширину. Прямые потомки текущего объекта загружаются при запросе на него в БД и в алгоритме я их могу перебрать:
Код: c#
1.
Groupu rootGroup = _context.Groupu.Include(g => g.InverseGroupParents).Include(g => g.GroupParents).FirstOrDefault(g => g.IdGroup==id);



Проблема в том, что не прямые потомки объекта, т.е. потомки потомков, которые хранятся в коллекциях прямых потомков, уже не загружаются, и я их перебрать уже не могу.

Как сделать, чтобы коллекции потомков подгружались?

Алгоритм, который используя для перебора потомков объекта:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
public List<Groupu> GetAllChildGroupsBFS(Groupu rootGroup, Groupu groupStart, Groupu goal)
        {
            // rootGroup - корневая группа
            // groupStart - начальный потомок
            // goal - пункт назначения, его нет

            // Список всех посещенных потомков
            List<Groupu> childGroupus = new List<Groupu>();

            // инициализируем очередь
            Queue<Groupu> queueGroupu = new Queue<Groupu>();
            // добавляем groupStart в очередь
            queueGroupu.Enqueue(rootGroup);

            while (queueGroupu.Count > 0)
            {
                // удаляем первый (верхний) элемент из очереди
                Groupu directChildgr = queueGroupu.Dequeue();
                //Добавляем посещенную вершину в список потомков
                childGroupus.Add(directChildgr);
                // rootGroup.InverseGroupParents - прямые потомки
                foreach (Groupu childgr in directChildgr.InverseGroupParents)
                {
                    // добавляем его в очередь
                    queueGroupu.Enqueue(childgr);
                
                }
            }
            // Возвращение списка потомков
            return childGroupus;
        }
...
Рейтинг: 0 / 0
17.08.2021, 17:28
    #40091298
Shocker.Pro
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
...
Рейтинг: 0 / 0
17.08.2021, 17:29
    #40091299
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
Насколько я знаю, ЕФ не может делать рекурсивные запросы. Тут как раз случай, когда имеет смысл делать прямой SQL-запрос с рекурсивным CTE (если это MS SQL). В других диалектах наверняка что-то подобное тоже есть.

https://docs.microsoft.com/en-us/ef/core/querying/raw-sql
...
Рейтинг: 0 / 0
17.08.2021, 17:30
    #40091302
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
Shocker.Pro
https://docs.microsoft.com/ru-ru/ef/core/querying/related-data/eager

Тут не прокатит, наверное, - у него кол-во уровней произвольное может быть (судя по схеме БД)
...
Рейтинг: 0 / 0
17.08.2021, 18:02
    #40091309
Shocker.Pro
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
fkthat
Тут не прокатит, наверное, - у него кол-во уровней произвольное может быть (судя по схеме БД)
Рекурсивно накатить ThenInclude раз двести )))

Вообще, если класс один и тот же, то что мешает грузануть все объекты в единую плоскую коллекцию, зачем обходить граф?
Понятно, что тогда элементам нужно знать свою принадлежность корневой сущности, но это обычно меньшее зло
...
Рейтинг: 0 / 0
17.08.2021, 18:23
    #40091311
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
Shocker.Pro
Вообще, если класс один и тот же, то что мешает грузануть все объекты в единую плоскую коллекцию, зачем обходить граф?

Тут изначально представление дерева в РБД сделано самым примитивным и неэффективным способом. Я бы посоветовал автору заглянуть в книгу "SQL Antipatterns" в главу "Naive Trees" - там описаны три намного лучших альтернативных способа.
...
Рейтинг: 0 / 0
17.08.2021, 18:40
    #40091312
petalvik
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
По-поводу рекурсивных запросов с CTE.

ORM linq2db позволяет делать таковые.

Если страшно вот так сразу перейти на сие божественное чудо с убогого EF (как же отказаться от поделия мелкософта?), то можно использовать библиотеку linq2db.EntityFrameworkCore .

Эта библиотека упомянута в списке EF Core Tools & Extensions .
...
Рейтинг: 0 / 0
17.08.2021, 19:08
    #40091317
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
petalvik
ORM linq2db позволяет делать таковые.

Ради пары запросов менять весь ORM?
...
Рейтинг: 0 / 0
17.08.2021, 20:20
    #40091329
Vlad__i__mir
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
fkthat
Shocker.Pro
Вообще, если класс один и тот же, то что мешает грузануть все объекты в единую плоскую коллекцию, зачем обходить граф?

Тут изначально представление дерева в РБД сделано самым примитивным и неэффективным способом. Я бы посоветовал автору заглянуть в книгу "SQL Antipatterns" в главу "Naive Trees" - там описаны три намного лучших альтернативных способа.


Тут уже поздно менять структуру - БД рабочая сданными, пользователи а ней уже работают
...
Рейтинг: 0 / 0
17.08.2021, 20:31
    #40091330
Vlad__i__mir
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
Shocker.Pro
fkthat
Тут не прокатит, наверное, - у него кол-во уровней произвольное может быть (судя по схеме БД)
Рекурсивно накатить ThenInclude раз двести )))

Вообще, если класс один и тот же, то что мешает грузануть все объекты в единую плоскую коллекцию, зачем обходить граф?
Понятно, что тогда элементам нужно знать свою принадлежность корневой сущности, но это обычно меньшее зло


Вот тут не понял, мне же нужны потомки одного конкретного объекта. Если я всех выгружу в List, то как мне это поможет.
Или вы имеете ввиду выгрузить всех, потом среди них найти нужного, а потом выбрать всех у кого в родителях стоит id нужного объекта?
А как тогда сохранить иерархию кто кому подчиняется внутри?
...
Рейтинг: 0 / 0
17.08.2021, 20:42
    #40091334
Vlad__i__mir
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
petalvik
По-поводу рекурсивных запросов с CTE.

ORM linq2db позволяет делать таковые.

Если страшно вот так сразу перейти на сие божественное чудо с убогого EF (как же отказаться от поделия мелкософта?), то можно использовать библиотеку linq2db.EntityFrameworkCore .

Эта библиотека упомянута в списке EF Core Tools & Extensions .


Не знаком с данной библиотекой. Могли бы вы показать как в моем случае должен выглядеть запрос?
...
Рейтинг: 0 / 0
17.08.2021, 21:56
    #40091348
Shocker.Pro
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
Vlad__i__mir
А как тогда сохранить иерархию кто кому подчиняется внутри?
Vlad__i__mir
Задача обойти всех потомков текущей группы до самого низа.
Если задача обойти, то с плоским списком это гораздо проще. Если задача какая-то другая, ее стоит озвучить
...
Рейтинг: 0 / 0
17.08.2021, 23:55
    #40091362
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
Vlad__i__mir
Тут уже поздно менять структуру - БД рабочая сданными, пользователи а ней уже работают

Тогда CTE. Впрочем, при желании, все эти паттерны из книги, что я выше упоминал ("Nested Sets", "Closure Table", и "Path Enumeration") можно реализовать и не меняя существующую структуру. Просто сделать нужную дополнительную таблица и триггера на таблицу с деревом, которая у тебя уже есть, для обновления этой дополнительной таблицы. Ни имеющийся код, ни имеющуюся схему менять при этом не придется.
...
Рейтинг: 0 / 0
18.08.2021, 03:04
    #40091372
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
Vlad__i__mir
Как сделать, чтобы коллекции потомков подгружались?


Забрать плоский список и собрать дерево на клиенте, не?


fkthat
Тогда CTE.


CTE вообще для другого. Чекайте: для фильтрации потомков и поиска предков.
...
Рейтинг: 0 / 0
18.08.2021, 04:59
    #40091379
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
hVostt
CTE вообще для другого.

CTE не " вообще для другого", а еще и для другого. Но, в том числе и для этого.
https://docs.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-ver15#examples
(См. Пример "D")
...
Рейтинг: 0 / 0
18.08.2021, 15:07
    #40091521
Vlad__i__mir
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
Shocker.Pro
Vlad__i__mir
А как тогда сохранить иерархию кто кому подчиняется внутри?
Vlad__i__mir
Задача обойти всех потомков текущей группы до самого низа.
Если задача обойти, то с плоским списком это гораздо проще. Если задача какая-то другая, ее стоит озвучить


Обойти и сохранить их в коллекцию в том порядке, в котором они идут - от самого высокого до того кто внизу структуры.

В принципе при вашем варианте это наверное тоже можно реализовать - сперва найти прямых потомков по id, потом искать их потомков по id уже найденных потомков, получается тоже рекурсия, правда пока точно не знаю как её реализовать
...
Рейтинг: 0 / 0
18.08.2021, 16:01
    #40091545
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
Vlad__i__mir
В принципе при вашем варианте это наверное тоже можно реализовать - сперва найти прямых потомков по id, потом искать их потомков по id уже найденных потомков, получается тоже рекурсия, правда пока точно не знаю как её реализовать

Блин. Я же тебе сказал - CTE. И ссылки дал. Вытягиваешь всех потомков рекурсивно одним запросом в коллекцию объектов. Потом эту коллекцию объектов обходишь. Обходить её чередой из 100500 запросов к серверу ты зашибешься.
...
Рейтинг: 0 / 0
20.08.2021, 13:57
    #40092245
ЕвгенийВ
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
Vlad__i__mir,
Давно, лет 100 назад, была такая задача.
Сделал sql функцию, возвращающую таблицу (Id, ParentId) и параметром самый первый Id.
Она легко вызывается и ее можно поджойнить в linq to entity запросе.
...
Рейтинг: 0 / 0
21.08.2021, 23:49
    #40092460
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как динамически загружать коллекций сущностей Entity Framework
ЕвгенийВ
Сделал sql функцию, возвращающую таблицу (Id, ParentId) и параметром самый первый Id.


Если я правильно понял, то второе поле это AncestorId
В общем-то да. Это всё, что нужно.
И вместо функции можно было сделать вьюху.
...
Рейтинг: 0 / 0
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / Как динамически загружать коллекций сущностей Entity Framework / 19 сообщений из 19, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]