Какую аннотацию я должен использовать: @IdClass или @EmbeddedId
The JPA (Java Persistence API) спецификация имеет 2 различных способа указать составные ключи сущности:@IdClass и @EmbeddedId.
Я использую обе аннотации на моих отображенных объектах, но это оказывается большой беспорядок для людей, которые не очень знакомы с JPA.
Я хочу принять только один способ определить составные ключи. Какой из них действительно лучший? Зачем?
7 ответов:
Я считаю, что
@EmbeddedIdвероятно, более подробно, потому что с@IdClassвы не можете получить доступ ко всему объекту первичного ключа с помощью любого оператора доступа к полю. Используя@EmbeddedIdможно сделать так:@Embeddable class EmployeeId { name, dataOfBirth } @Entity class Employee { @EmbeddedId EmployeeId employeeId; ... }это дает четкое представление о полях, которые составляют составной ключ, потому что все они агрегируются в классе, доступ к которому осуществляется через оператор доступа к полю.
еще одна разница с
@IdClassи@EmbeddedIdэто когда дело доходит до написания HQL :С
@IdClassвы пишете:select e.name from Employee eи
@EmbeddedIdвы должны написать:select e.employeeId.name from Employee eвы должны написать больше текста для того же запроса. Некоторые могут возразить, что это отличается от более естественного языка, как тот, который продвигается
IdClass. Но в большинстве случаев понимание прямо из запроса, что данное поле является частью составного ключа, имеет неоценимую помощь.
Я обнаружил экземпляр, где мне пришлось использовать EmbeddedId вместо IdClass. В этом случае существует объединенная таблица, в которой определены дополнительные столбцы. Я попытался решить эту проблему с помощью IdClass для представления ключа сущности, которая явно представляет строки в таблице соединения. Я не мог заставить его работать таким образом. К счастью, "Java Persistence With Hibernate" имеет раздел, посвященный этой теме. Одно из предложенных решений было очень похоже на мое, но вместо этого он использовал EmbeddedId. Я моделируется мои объекты после тех, в книге он теперь ведет себя правильно.
существует три стратегии использования составного первичного ключа:
- пометить как
@Embeddableи добавьте к своему классу сущностей нормальное свойство для него, отмеченное@Id.- добавьте в свой класс сущностей обычное свойство для него, отмеченное
@EmbeddedId.- добавьте свойства в свой класс сущностей для всех его полей, отметьте их
@Id, и отметьте свой класс сущности с@IdClass, поставляя класс вашего первичного ключа класс.использование
@IdС классом, помеченным как@EmbeddableЭто самый естественный подход. Элемент@Embeddableтег может быть использован для не первичного ключа встраиваемых значений в любом случае. Это позволяет рассматривать составной первичный ключ как одно свойство, и это позволяет повторно использовать@Embeddableкласса в других таблицах.следующим наиболее естественным подходом является использование
@EmbeddedIdтег. Здесь класс первичного ключа не может использоваться в других таблицах, так как он не является@Embeddableсущность, но она позволяет нам рассматривать ключ как один атрибут некоторого класса.наконец, использование
@IdClassи@Idаннотации позволяют сопоставить составной класс первичного ключа, используя свойства самой сущности, соответствующие именам свойств в классе первичного ключа. Имена должны соответствовать (нет механизма для переопределения этого), и класс первичного ключа должен выполнять те же обязательства, что и с двумя другими методами. Единственный преимуществом такого подхода является его способность "скрывать" использование класса первичного ключа от интерфейса заключающей сущности. Элемент@IdClassаннотация принимает параметр значения типа класса, который должен быть классом, используемым в качестве составного первичного ключа. Поля, соответствующие свойствам используемого класса первичного ключа, должны быть аннотированы с помощью@Id.
насколько я знаю, если ваш композитный ПК содержит FK, его проще и проще использовать
@IdClassС
@EmbeddedIdвы должны определить отображение для вашего столбца FK дважды, onece в@Embeddedableи раз для как т. е.@ManyToOneздесь@ManyToOneдолжен быть только для чтения(@PrimaryKeyJoinColumn), потому что вы не можете иметь один столбец из двух переменных (возможные конфликты).
Таким образом, вы должны установить свой FK с помощью простого типа в@Embeddedable.на другом сайте с помощью
@IdClassэтот ситуация может быть обработана гораздо проще, как показано в первичные ключи через Onetoone и ManyToOne отношения:пример JPA 2.0 manytoone id аннотация
... @Entity @IdClass(PhonePK.class) public class Phone { @Id private String type; @ManyToOne @Id @JoinColumn(name="OWNER_ID", referencedColumnName="EMP_ID") private Employee owner; ... }пример JPA 2.0 id class
... public class PhonePK { private String type; private long owner; public PhonePK() {} public PhonePK(String type, long owner) { this.type = type; this.owner = owner; } public boolean equals(Object object) { if (object instanceof PhonePK) { PhonePK pk = (PhonePK)object; return type.equals(pk.type) && owner == pk.owner; } else { return false; } } public int hashCode() { return type.hashCode() + owner; } }
Я думаю, что главное преимущество заключается в том, что мы могли бы использовать
@GeneratedValueдля идентификатора при использовании@IdClass? Я уверен, что мы не можем использовать@GeneratedValueна@EmbeddedId.
С EmbeddedId вы можете использовать предложение IN в HQL, например:
FROM Entity WHERE id IN :idsгде id является EmbeddedId тогда как это боль, чтобы достичь того же результата с IdClass вы хотите сделать что-то вродеFROM Entity WHERE idPartA = :idPartA0 AND idPartB = :idPartB0 .... OR idPartA = :idPartAN AND idPartB = :idPartBN
Comments