Я думаю о макете таблицы для иерархии классов, управляемой Hibernate, и, конечно, метод таблицы на подклассы кажется мне наиболее подходящим в общем смысле. Однако, продумывая логику, я испытываю некоторые сомнения по поводу ее производительности, особенно в том, что касается количества подклассов.
Чтобы привести очень краткий (и классический) пример, допустим, у вас есть следующие классы:
public abstract class Animal {
int pkey;
String name;
}
public class Dog extends Animal {
long numSlippersChewed; // int is not large enough...
}
public class Cat extends Animal {
short miceCaught; // ... but here int is far bigger than required :-)
}
(я выбираю геттеры и сеттеры, отображения Hibernate и т. Д., Просто предположим, что это основной очевидный случай).
Таблицы базы данных для этих сущностей имеют смысл, вы получаете хорошую денормализацию и так далее. Однако, какой запрос делает Hibernate, чтобы вытащить отдельное животное? Я могу вспомнить как минимум два случая, когда это может произойти:
- Некоторая другая сущность, имеющая отображение один-к-одному (или один-ко-многим), например поле
pet
класса Human
. Это будет хранить pkey, поэтому, когда Hibernate выбирает объект Human, ему также нужно будет извлечь соответствующий объект Animal
. Когда задан ключ животного, какой запрос (и) будет использовать Hibernate для извлечения и снятия с нуля фактических данных Animal, учитывая, что они могут находиться в таблицах Cat
или Dog
?
- HQL, такой как
from Animal where name='Rex'
(предположим, имена уникальны). Это похоже на вышесказанное в том, что оно позволяет вам идентифицировать строку в таблице суперкласса, но вы не знаете, какую таблицу подкласса нужно проверить для получения дополнительной информации. Позволяет ли HQL даже выдавать запрос from
абстрактный класс? (Использование специфичных для подклассов вещей работает хорошо, например, from Cat where miceCaught > 5
).
Я могу придумать два способа, которыми это можно сделать в SQL, и ни один из них не выглядит симпатичным. Один из них - запустить запрос exists
для каждой таблицы подклассов для данного ключа и затем загрузить из таблицы, которая вернула попадание. В качестве альтернативы Hibernate мог бы выполнить какое-то ужасное объединение запросов объединения во всех таблицах - по сути, имитируя схему таблицы на иерархию, в которой результирующий набор включал бы атрибуты для всех возможных подклассов с отдельными выборками из таблиц подклассов, возвращая null
для неактуальных аргументы. В последнем случае, возможно, даже потребуется добавить синтетический столбец дискриминатора, чтобы Hibernate мог знать, какая таблица подклассов действительно вернула строку и, следовательно, в какой класс Java они должны быть проанализированы.
Вещи становятся более опасными, если у вас есть подтипы конкретных типов:
public class Greyhound extends Dog {
float lifetimeRacingWinnings;
}
Теперь для данного животного pkey могут быть допустимые строки в таблицах Dog
и Greyhound
, что означает, что мой первый подход ручной проверки класса, соответствующего pkey, получает много жестче.
Причина, по которой я так обеспокоен, заключается в том, что я захочу использовать этот подход в иерархии классов, включающей около 70 классов с максимальной цепочкой вложений 4-5 уровней, поэтому выполнение запроса объединения по всем этим вероятно иметь ужасную производительность. Есть ли у Hibernate какие-то хитрости, чтобы сохранить это относительно быстрым? Или загрузка ссылки на один из этих классов pkey займет много времени?