Почему @ForceDiscriminator
или его эквивалент @DiscriminatorOptions(force=true)
необходимо в некоторых случаях наследования и полиморфных ассоциаций? Кажется, это единственный способ получить работу. Есть ли причины не использовать его?
Об использовании @ForceDiscriminator/@DiscriminatorOptions (force = true)
Ответ 1
Поскольку я снова и снова сталкиваюсь с этим, я думаю, что это может помочь прояснить:
Во-первых, это правда, что Hibernate не требует дискриминации при использовании отображения JOINED_TABLE
. Однако это необходимо при использовании SINGLE_TABLE
. Что еще более важно, другие провайдеры JPA в основном требуют этого.
То, что Hibernate на самом деле делает при выполнении полиморфного запроса JOINED_TABLE
, заключается в создании дискриминатора с именем clazz
"на лету" с использованием case-switch, который проверяет наличие уникальных полей для конкретных подклассов после внешнего соединения всех таблиц участвует в дереве наследования. Вы можете видеть это, когда включаете свойство "hibernate.show_sql"
в свой persistence.xml
. На мой взгляд, это, вероятно, идеальное решение для запросов JOINED_TABLE
, поэтому люди Hibernate могут похвастаться этим.
При выполнении обновлений и удалений этот вопрос несколько отличается; здесь hibernate сначала запрашивает вашу корневую таблицу для любых ключей, которые соответствуют предложению where where, и создает виртуальный pkTable
из результата. Затем он выполняет "DELETE FROM / UPDATE table WHERE pk IN pkTable"
для любого конкретного класса с вашим деревом наследования; оператор IN вызывает отсканированный подзапрос O(log(N))
для каждой записи таблицы, но, скорее всего, это в памяти, поэтому это не так уж плохо с точки зрения производительности.
Чтобы ответить на ваш конкретный вопрос, Hibernate просто не видит здесь проблемы, и с определенной точки зрения они верны. Было бы невероятно просто прокомментировать аннотации @DiscriminatorValue
, введя значения дискриминатора во время entityManager.persist()
, даже если они на самом деле их не используют. Однако не соблюдение столбца дискриминатора в JOINED_TABLE
имеет преимущество (для Hibernate) для создания мягкого случая блокировки поставщика, и это даже оправданно, указывая на превосходную технологию.
@ForceDiscriminator
или @DiscriminatorOptions(force=true)
уверены, что немного облегчают боль, но вы должны использовать их до создания первых объектов или принудительно вручную добавлять отсутствующие значения дискриминатора с помощью операторов SQL. Если вы смеете отойти от Hibernate, это, по крайней мере, потребует некоторого изменения кода для удаления этих аннотаций Hibernate, создающих устойчивость к миграции. И это, очевидно, все, что Hibernate волнует в этом случае.
По моему опыту, lockin - это рай, на котором все самые смелые мечты любого лидера рынка, потому что это волшебная палочка макиавелли, которая защищает долю рынка без усилий; таким образом, это делается, когда клиенты не сопротивляются и не влияют на продавца, который выше, чем выгоды, получаемые. Кто сказал, что мир с открытым исходным кодом будет другим?
p.s, просто чтобы избежать путаницы: я никоим образом не связан с каким-либо разработчиком JPA.
p.p.s: то, что я обычно делаю, игнорирует проблему до момента миграции; вы можете затем сформулировать инструкцию SQL UPDATE ... FROM
, используя тот же самый трюк case-switch-with-outer-join, который использует Hibernate для заполнения отсутствующих значений дискриминатора. Это действительно легко, как только вы поняли основной принцип.
Ответ 2
Ребята позвольте мне попытаться объяснить о @DiscriminatorOptions(Force=true)
.
Ну, он используется в наследовании одиночной таблицы, я недавно использовал это в одном из сценариев.
У меня есть два объекта, которые были сопоставлены с одной таблицей. когда я пытался извлечь запись для одного объекта, я получал список результирующих записей из обоих сущностей, и это была моя проблема. Для решения этой проблемы я использовал @DiscriminatorOptions(Force=true)
, который создаст предикат, используя столбец Discriminator с указанным значением, сопоставленным соответствующему объекту.
поэтому запрос будет выглядеть так, как только я использовал @DiscriminatorOptions(Force=true)
select *
from TABLE
where YOUR PREDICATE AND DiscriminatorColumn = DiscriminatorValue
Ответ 3
Я думаю, что это больше мое мнение, но я думаю, что некоторые согласятся со мной. Я предпочитаю, что Hibernate позволяет вам не использовать дискриминатор. В некоторых случаях дискриминатор не нужен.
Например, у меня есть объект Person
, который содержит такие вещи, как имя, дату рождения и т.д. Этот объект может использоваться несколькими другими объектами, такими как Employee
или Customer
. Когда я не ссылаюсь на Person
на другие объекты, но вместо ссылки Employee
или Customer
, дискриминатор не используется, так как Hibernate получает запрос на выбор одного из них.
Ответ 4
@yannisf ForceDiscriminator - не единственное решение для решения этой проблемы.
Вы можете делать экземпляры тестов для каждого дочернего класса. Хотя это будет похоже на жесткое кодирование ваших классов в вашем коде, но это более чистый способ решить проблему, если столбец дискриминатора не заполнен.
Это также помогает вашему коду избежать смешивания аннотаций jpa и hibernate.
Как указано yannisf, instanceOf является своего рода антипаттерном в мире OO.
Другим решением может быть изменение отображения сущности. Предположим, что сущность A имеет ссылку на суперкласс B и B имеет дочерние классы типа C1 и C2, вместо A, указывающие на B, вы можете иметь C1 и C2 иметь внешний ключ, указывающий на A. Все сводится к изменению дизайн объекта, чтобы не смешивать аннотации.
Спасибо Vaibhav