EF6 code first, загрузка наследников, огромный select union
От: Osaka  
Дата: 27.04.22 17:04
Оценка:
Есть модель EF из C#-классов, допустим, с базовым типом и 100 наследников различной степени вложенности.
Маппинг "таблица на конкретный тип" (каждая таблица содержи только записи своего типа, и все поля всех предков).
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {

            modelBuilder.Entity<Base>()
                .Map<Child1>(m =>
                {
                    m.ToTable("Child1");
                    m.MapInheritedProperties();
                })
                .Map<Child2>(m =>
                {
                    m.ToTable("Child2");
                    m.MapInheritedProperties();
                })
                ....

Читаем в модель через DBSet все строки типа Base.
В некоторых случаях EF генерит простой sql "select ... from Base", а в других — огромный развесистый union всех наследных типов. (Размер sql-запроса может достигать сотен kb, и ползает всё это неприлично долго).
От чего зависит это поведение? Я пока обнаружил только что наследные типы включаются в запрос если в иерархии сущностей присутствуют абстрактные классы.
Можно ли данным поведением управлять не меняя модель, а в рантайме, по-разному для разных типов и навигационных свойств?
Друга ищи не того, кто любезен с тобой, кто с тобой соглашается, а крепкого советника, кто полезного для тебя ищет и противится твоим необдуманным словам.
Re: EF6 code first, загрузка наследников, огромный select union
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 27.04.22 18:50
Оценка: +1
Здравствуйте, Osaka, Вы писали:

O>Есть модель EF из C#-классов, допустим, с базовым типом и 100 наследников различной степени вложенности.

O>Маппинг "таблица на конкретный тип" (каждая таблица содержи только записи своего типа, и все поля всех предков).
O>Читаем в модель через DBSet все строки типа Base.
Очевидно это потребует чтения всех таблиц и union all
Как иначе получить все экземпляры, унаследованные от base?

O>В некоторых случаях EF генерит простой sql "select ... from Base", а в других — огромный развесистый union всех наследных типов. (Размер sql-запроса может достигать сотен kb, и ползает всё это неприлично долго).

O>От чего зависит это поведение? Я пока обнаружил только что наследные типы включаются в запрос если в иерархии сущностей присутствуют абстрактные классы.
Покажи код запроса и какой sql он генеирует, пока непонятно является ли такой SQL избыточным или он генерирует ровно то, что нужно.

O>Можно ли данным поведением управлять не меняя модель, а в рантайме, по-разному для разных типов и навигационных свойств?

Можно, если сделать проекцию.
Re: EF6 code first, загрузка наследников, огромный select union
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 27.04.22 18:51
Оценка:
Слона не приметил... EF6 это же не EfCore6?
Я бы от первого отказался в пользу второго.
Re: EF6 code first, загрузка наследников, огромный select union
От: Danchik Украина  
Дата: 28.04.22 19:16
Оценка: 2 (1)
Здравствуйте, Osaka, Вы писали:

O>От чего зависит это поведение? Я пока обнаружил только что наследные типы включаются в запрос если в иерархии сущностей присутствуют абстрактные классы.

O>Можно ли данным поведением управлять не меняя модель, а в рантайме, по-разному для разных типов и навигационных свойств?

OfType пробовал?

context.Set<Base>().OfType<Child2>().ToList();
Re[2]: EF6 code first, загрузка наследников, огромный select union
От: Osaka  
Дата: 28.04.22 20:13
Оценка:
G>непонятно является ли такой SQL избыточным или он генерирует ровно то, что нужно.
Математически там всё верно, вытаскивает все наследные типы. Но мне это в одних задачах нужно, а в других недопустимо.

O>>Можно ли данным поведением управлять не меняя модель, а в рантайме, по-разному для разных типов и навигационных свойств?

G>Можно, если сделать проекцию.
"Проекция" в данном контексте это что?
Друга ищи не того, кто любезен с тобой, кто с тобой соглашается, а крепкого советника, кто полезного для тебя ищет и противится твоим необдуманным словам.
Re[2]: EF6 code first, загрузка наследников, огромный select union
От: Osaka  
Дата: 28.04.22 20:15
Оценка:
G>Слона не приметил... EF6 это же не EfCore6?
G>Я бы от первого отказался в пользу второго.
Чем он лучше?
Читал что-то про это EF Core несколько лет назад, они обещали когда-нибудь научиться делать всё что умеет древний EF, но наследование таблиц не умели. Сдвинулось что-то с этим вопросом?
Друга ищи не того, кто любезен с тобой, кто с тобой соглашается, а крепкого советника, кто полезного для тебя ищет и противится твоим необдуманным словам.
Re[2]: EF6 code first, загрузка наследников, огромный select union
От: Osaka  
Дата: 28.04.22 20:30
Оценка:
D>OfType пробовал?
D>
D>context.Set<Base>().OfType<Child2>().ToList();
D>

В некотором смысле работает. Позволяет ограничить вычитываемую иерархию указанным типом и его наследниками. Но только если модель такая, что sql union вообще генерится. Я этого достиг тем, что в иерархии есть абстрактные классы (каждый Child N наследуется от abstract ChildNBase:ChildN-1). А если абстрактные классы добавить в modelbuilder.Ignore, то sql union не генерится, OfType выдаёт ошибку DbOfTypeExpression requires an expression argument with a polymorphic result type that is compatible with the type argument.
По-прежнему непонятно, по какому признаку EF решает, что надо тащить через 1 sql всех наследников, а не только указанный тип.
Друга ищи не того, кто любезен с тобой, кто с тобой соглашается, а крепкого советника, кто полезного для тебя ищет и противится твоим необдуманным словам.
Re[3]: EF6 code first, загрузка наследников, огромный select union
От: Danchik Украина  
Дата: 29.04.22 04:03
Оценка:
Здравствуйте, Osaka, Вы писали:

G>>Слона не приметил... EF6 это же не EfCore6?

G>>Я бы от первого отказался в пользу второго.

O>Чем он лучше?

O>Читал что-то про это EF Core несколько лет назад, они обещали когда-нибудь научиться делать всё что умеет древний EF, но наследование таблиц не умели. Сдвинулось что-то с этим вопросом?

Лучше спроектирован, быстрее, запросы эффективнее. TPT есть, но и они же предупреждают что это очень неэффективной способ хранения данных.
Минус что для новых версии надо апдейтится к .NET 6
Re[3]: EF6 code first, загрузка наследников, огромный select union
От: Danchik Украина  
Дата: 29.04.22 04:05
Оценка:
Здравствуйте, Osaka, Вы писали:

D>>OfType пробовал?

D>>
D>>context.Set<Base>().OfType<Child2>().ToList();
D>>

O>В некотором смысле работает. Позволяет ограничить вычитываемую иерархию указанным типом и его наследниками. Но только если модель такая, что sql union вообще генерится. Я этого достиг тем, что в иерархии есть абстрактные классы (каждый Child N наследуется от abstract ChildNBase:ChildN-1). А если абстрактные классы добавить в modelbuilder.Ignore, то sql union не генерится, OfType выдаёт ошибку DbOfTypeExpression requires an expression argument with a polymorphic result type that is compatible with the type argument.
O>По-прежнему непонятно, по какому признаку EF решает, что надо тащить через 1 sql всех наследников, а не только указанный тип.

Мой кристальный шар сегодня сломался. Могу гадать только по реальным LINQ запросам.
Re[3]: EF6 code first, загрузка наследников, огромный select union
От: Danchik Украина  
Дата: 29.04.22 04:10
Оценка:
Здравствуйте, Osaka, Вы писали:

G>>непонятно является ли такой SQL избыточным или он генерирует ровно то, что нужно.

O>Математически там всё верно, вытаскивает все наследные типы. Но мне это в одних задачах нужно, а в других недопустимо.

O>>>Можно ли данным поведением управлять не меняя модель, а в рантайме, по-разному для разных типов и навигационных свойств?

G>>Можно, если сделать проекцию.
O>"Проекция" в данном контексте это что?

Проекция это когда выбрасываются Include и пишется хардкорный Select )
Re: EF6 code first, загрузка наследников, огромный select union
От: vaa  
Дата: 29.04.22 04:27
Оценка:
Здравствуйте, Osaka, Вы писали:

O>Есть модель EF из C#-классов, допустим, с базовым типом и 100 наследников различной степени вложенности.

O>Маппинг "таблица на конкретный тип" (каждая таблица содержи только записи своего типа, и все поля всех предков).
O>В некоторых случаях EF генерит простой sql "select ... from Base", а в других — огромный развесистый union всех наследных типов. (Размер sql-запроса может достигать сотен kb, и ползает всё это неприлично долго).

Разве не очевидно?
Первое: есть профит реальный от наследования? Если да, то лучше в одной таблице все держать.
Иначе, лучше использовать независимые типы или композицию один к одному.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[3]: EF6 code first, загрузка наследников, огромный select union
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 29.04.22 10:04
Оценка:
Здравствуйте, Osaka, Вы писали:

G>>Слона не приметил... EF6 это же не EfCore6?

G>>Я бы от первого отказался в пользу второго.
O>Чем он лучше?
Чуть менее чем всем

O>Читал что-то про это EF Core несколько лет назад, они обещали когда-нибудь научиться делать всё что умеет древний EF, но наследование таблиц не умели. Сдвинулось что-то с этим вопросом?

https://docs.microsoft.com/en-us/ef/core/modeling/inheritance#table-per-type-configuration
Re[3]: EF6 code first, загрузка наследников, огромный select union
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 29.04.22 10:05
Оценка:
Здравствуйте, Osaka, Вы писали:

G>>непонятно является ли такой SQL избыточным или он генерирует ровно то, что нужно.

O>Математически там всё верно, вытаскивает все наследные типы. Но мне это в одних задачах нужно, а в других недопустимо.
Так ты в каждой конкретной задаче указывай что нужно, то и будет вытаскивать.

O>>>Можно ли данным поведением управлять не меняя модель, а в рантайме, по-разному для разных типов и навигационных свойств?

G>>Можно, если сделать проекцию.
O>"Проекция" в данном контексте это что?
.Select с явным указанием нужных полей.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.