Об использовании @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