Hibernate генерирует несколько JOIN в запросе с предложением WHERE для сущностей из наследования одной таблицы. ⇐ JAVA
-
Anonymous
Hibernate генерирует несколько JOIN в запросе с предложением WHERE для сущностей из наследования одной таблицы.
В нашем приложении мы используем стратегию наследования одной таблицы в режиме гибернации, чтобы различать типы сравнения во время запроса.
Поскольку наше программное обеспечение не является открытым исходным кодом, я постараюсь максимально абстрагировать нашу реализацию.
Наша модель сущности в данном случае состоит из двух таблиц, одна из которых — ParentEntity, имеющая несколько дочерних объектов.
Реализация этих объектов в Java выглядит примерно так:
@Entity @Table(имя = TableEntity.TBL_NAME) общественный класс TableEntity { … } @Сущность @Table(имя = ParentEntity.TBL_NAME) @Inheritance (стратегия = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn (имя = «PARENT_ATTR») публичный абстрактный класс ParentEntity { … } @Сущность @DiscriminatorValue(“CHILD_ENTITY_1) общественный класс ChildEntity1 расширяет ParentEntity { … } @Сущность @DiscriminatorValue("CHILD_ENTITY_2") общественный класс ChildEntity2 расширяет ParentEntity { … } TableEntity — это то, что мы пытаемся запросить.
ParentEntity — это объединенный тип сравнения, помеченный как SingleTableInheritance.
ChildEntity расширяет ParentEntity одним дополнительным полем.
Мы используем стратегию наследования одной таблицы для повышения производительности и потому, что мы не хотим, чтобы количество таблиц в нашей БД переполнялось.
Поскольку мы используем относительно сложный механизм фильтрации, мы объединяем множество предикатов в один более крупный запрос с критериями.
Вызов метода для предиката выглядит примерно так:
Join join = tableEntityRoot.join(TableEntity.joinAttribute); predicates.add(cb.equal(cb.treat(join, ChildEntity1.class).get(ChildEntity1.CHILD_ATTR_1), сравнениеValue)); predicates.add(cb.equal(cb.treat(join, ChildEntity2.class).get(ChildEntity2.CHILD_ATTR_2), сравнениеValue)); TableEntity и ParentEntity объединены.
Предикаты предложенияwhere создаются на основе полей, представленных ChildEntities.
Оператор «обработка» необходим для сопоставления ChildEntities с ParentEntity. В противном случае спящий режим не будет знать, что объединение имеет поля ChildEntities.
При выполнении этого запроса я бы исключил переход в спящий режим для создания одного соединения между TableEntity и ParentEntity, поскольку мы используем стратегию наследования одной таблицы в спящем режиме.
Результирующий запрос выглядит примерно так:
выберите * из ТАБЛИЦЫ t внутреннее соединение PARENT_TABLE pt1 по t.PT_ID = pt1.PT_ID внутреннее соединение PARENT_TABLE pt2 по t.PT_ID = pt2.PT_ID внутреннее соединение PARENT_TABLE pt3 по t.PT_ID = pt3.PT_ID внутреннее соединение PARENT_TABLE pt4 по t.PT_ID = pt4.PT_ID … где (pt1.PARENT_ATTR в (…)) и (p2.CHILD_ATTR_1 = значение сравнения или p3.CHILD_ATTR_2 = значение сравнения или p4.CHILD_ATTR_3 = значение сравнения ); PARENT_TABLE объединяется один раз для каждого имеющегося у него наследования первого уровня. Для одной и той же таблицы существует несколько объединений.
Такое поведение вызывает проблемы при выполнении предложенияwhere, поскольку сами предложения могут быть правильными, а комбинация — нет. В частности, сочетание предложений «где в» и «равно» дает противоречивые результаты.
В частности, проблема возникает из-за оператора «обработка», поскольку без него выполняется только одно соединение. Однако если вы опустите оператор «обработка», спящий режим вызовет исключение, поскольку не сможет найти поля ChildEntity.
Я провел немало исследований по этому поводу в Интернете, но ничего не нашел и сейчас немного в растерянности. Помощь будет оценена по достоинству.
В нашем приложении мы используем стратегию наследования одной таблицы в режиме гибернации, чтобы различать типы сравнения во время запроса.
Поскольку наше программное обеспечение не является открытым исходным кодом, я постараюсь максимально абстрагировать нашу реализацию.
Наша модель сущности в данном случае состоит из двух таблиц, одна из которых — ParentEntity, имеющая несколько дочерних объектов.
Реализация этих объектов в Java выглядит примерно так:
@Entity @Table(имя = TableEntity.TBL_NAME) общественный класс TableEntity { … } @Сущность @Table(имя = ParentEntity.TBL_NAME) @Inheritance (стратегия = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn (имя = «PARENT_ATTR») публичный абстрактный класс ParentEntity { … } @Сущность @DiscriminatorValue(“CHILD_ENTITY_1) общественный класс ChildEntity1 расширяет ParentEntity { … } @Сущность @DiscriminatorValue("CHILD_ENTITY_2") общественный класс ChildEntity2 расширяет ParentEntity { … } TableEntity — это то, что мы пытаемся запросить.
ParentEntity — это объединенный тип сравнения, помеченный как SingleTableInheritance.
ChildEntity расширяет ParentEntity одним дополнительным полем.
Мы используем стратегию наследования одной таблицы для повышения производительности и потому, что мы не хотим, чтобы количество таблиц в нашей БД переполнялось.
Поскольку мы используем относительно сложный механизм фильтрации, мы объединяем множество предикатов в один более крупный запрос с критериями.
Вызов метода для предиката выглядит примерно так:
Join join = tableEntityRoot.join(TableEntity.joinAttribute); predicates.add(cb.equal(cb.treat(join, ChildEntity1.class).get(ChildEntity1.CHILD_ATTR_1), сравнениеValue)); predicates.add(cb.equal(cb.treat(join, ChildEntity2.class).get(ChildEntity2.CHILD_ATTR_2), сравнениеValue)); TableEntity и ParentEntity объединены.
Предикаты предложенияwhere создаются на основе полей, представленных ChildEntities.
Оператор «обработка» необходим для сопоставления ChildEntities с ParentEntity. В противном случае спящий режим не будет знать, что объединение имеет поля ChildEntities.
При выполнении этого запроса я бы исключил переход в спящий режим для создания одного соединения между TableEntity и ParentEntity, поскольку мы используем стратегию наследования одной таблицы в спящем режиме.
Результирующий запрос выглядит примерно так:
выберите * из ТАБЛИЦЫ t внутреннее соединение PARENT_TABLE pt1 по t.PT_ID = pt1.PT_ID внутреннее соединение PARENT_TABLE pt2 по t.PT_ID = pt2.PT_ID внутреннее соединение PARENT_TABLE pt3 по t.PT_ID = pt3.PT_ID внутреннее соединение PARENT_TABLE pt4 по t.PT_ID = pt4.PT_ID … где (pt1.PARENT_ATTR в (…)) и (p2.CHILD_ATTR_1 = значение сравнения или p3.CHILD_ATTR_2 = значение сравнения или p4.CHILD_ATTR_3 = значение сравнения ); PARENT_TABLE объединяется один раз для каждого имеющегося у него наследования первого уровня. Для одной и той же таблицы существует несколько объединений.
Такое поведение вызывает проблемы при выполнении предложенияwhere, поскольку сами предложения могут быть правильными, а комбинация — нет. В частности, сочетание предложений «где в» и «равно» дает противоречивые результаты.
В частности, проблема возникает из-за оператора «обработка», поскольку без него выполняется только одно соединение. Однако если вы опустите оператор «обработка», спящий режим вызовет исключение, поскольку не сможет найти поля ChildEntity.
Я провел немало исследований по этому поводу в Интернете, но ничего не нашел и сейчас немного в растерянности. Помощь будет оценена по достоинству.
Мобильная версия