Стратегия наследования Hibernate и почему

У меня есть 3 неабстрактных устойчивых класса. Классы MyClubUser и HisClubUser наследуются от класса User. Я использую одну таблицу для стратегии каждого подкласса, т.е. @Inheritance(strategy = InheritanceType.JOINED), для этих классов.

Я заметил, что сгенерированный SQL использует левое внешнее соединение HisClubUser и MyClubUser, когда я делаю запрос к классу User. Почему Hibernate делает это [присоединение к другим таблицам], когда меня интересует только Пользователь? Я хочу сказать, что даже если данные получены, я не смогу получить доступ к этим свойствам в MyClubUser или HisClubUser, учитывая, что экземпляры User возвращаются. Кроме того, вызывает ли это дополнительные накладные расходы по сравнению с запросом, в котором он просто запрашивает таблицу User без левого внешнего соединения?

Спасибо


person thlim    schedule 07.10.2009    source источник


Ответы (3)


Hibernate ВСЕГДА возвращает фактический тип сохраняемой сущности. Если вы сохранили «MyClubUser», он будет возвращен как «MyClubUser», а не как «Пользователь». Причина этого довольно ясна - если Hibernate вернет «MyClubUser» как «User», и вы снова сохраните его, вы потеряете все дополнительные свойства, определенные в «MyClubUser».

Для этого Hibernate необходимо знать, что это за фактический тип. Для стратегии InheritanceType.JOINED единственный способ выяснить это - проверить все таблицы в вашей иерархии наследования (ну, технически это все таблицы на текущем уровне или ниже, плюс все таблицы выше текущего уровня в текущей ветке дерева) . Итак, если у вас есть такая иерархия:

           Root
          /   \
      Node1  Node2
      /   \
   Node11 Node12

и вы пытаетесь выбрать из корня, Hibernate выполнит внешнее соединение для ВСЕХ таблиц. Если вы выбираете из Node1, Hibernate выполнит внутреннее соединение на Node1 и Root, а также внешнее соединение на Node11 и Node12. Узел 2 не будет затронут, потому что он не является потомком узла 1.

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

person ChssPly76    schedule 07.10.2009
comment
+1 Большое спасибо за эти детали, они прояснили, почему мое первоначальное предложение SimpleUser не работает с InheritanceType.JOINED. Я удалил эту часть из своего ответа, чтобы никого не вводить в заблуждение. - person KLE; 08.10.2009

Почему Hibernate делает это [присоединение к другим таблицам], когда меня интересует только Пользователь?

Поскольку все HisClubUser также являются действительными экземплярами User, логично получить их, когда вы запросите User.

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

Вы действительно уверены? Проверьте (например, при отладке) возвращаемый эффективный класс, это должны быть подклассы. Таким образом, возможен переход вниз и доступ к свойствам.

Кроме того, вызывает ли это дополнительные накладные расходы по сравнению с запросом, в котором он просто запрашивает таблицу User без левого внешнего соединения?

Да, и дополнительное соединение имеет накладные расходы. Это может быть важно или нет: я предлагаю вам протестировать это в вашем конкретном случае.

person KLE    schedule 07.10.2009
comment
+1. Однако вам, вероятно, следует удалить предложение SimpleUser, так как оно не поможет; Я объяснил почему в своем ответе. - person ChssPly76; 07.10.2009
comment
@ ChssPly76 Спасибо. Я прочитал ваш ответ и теперь точно понимаю, почему. Ты прав :-) - person KLE; 08.10.2009
comment
Спасибо, ребята ... Теперь я понимаю. Что я сейчас делаю, так это MyClubUser и HisClubUser будут иметь отношения 1 к 1 с пользователем вместо наследования от пользователя. Чтобы получить доступ к дополнительным свойствам в MyClubUSer и HisClubUser, я снова запрошу. Пользователь для входа в систему. В большинстве случаев используются определенные классы. Иногда считываются свойства в User. @KLE Я уверен. Запрос возвращает только User, что имеет смысл. Если приведение вниз возможно, то пользователь должен унаследовать MyClubUser и HisClubUser, что невозможно. - person thlim; 10.10.2009

Вы запрашиваете пользователя, поэтому Hibernate выполнит «полиморфный запрос». Поскольку MyClubUser и HisClubUser по своей природе являются объектами User (они наследуются от User), Hibernate также будет извлекать таких пользователей.

person Frederik Gheysels    schedule 07.10.2009