Какую аннотацию следует использовать: @IdClass или @EmbeddedId
Спецификация JPA
(Java Persistence API) имеет два разных способа указать составные ключи сущностей: @IdClass
и @EmbeddedId
.
Я использую оба аннотации для своих образованных объектов, но, похоже, это большой беспорядок для людей, которые не очень хорошо знакомы с JPA
.
Я хочу использовать только один способ указания составных клавиш. Какой из них действительно лучший? Почему?
Ответы
Ответ 1
Я считаю, что @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
. Но большую часть времени, понимая прямо из запроса, что данное поле является частью составного ключа, имеет неоценимую помощь.
Ответ 2
Я обнаружил экземпляр, где мне пришлось использовать EmbeddedId вместо IdClass. В этом случае есть таблица соединений, в которой указаны дополнительные столбцы. Я попытался решить эту проблему, используя IdClass, чтобы представить ключ объекта, который явно представляет строки в таблице соединений. Я не мог заставить его работать таким образом. К счастью, "Java Persistence With Hibernate" имеет раздел, посвященный этой теме. Одно предлагаемое решение было очень похоже на мое, но вместо этого оно использовало EmbeddedId. Я смоделировал свои объекты после того, как в книге он теперь ведет себя правильно.
Ответ 3
Насколько я знаю, если ваш составной ПК содержит FK, проще и проще использовать @IdClass
С @EmbeddedId
вам нужно дважды определить сопоставление для своего столбца FK, один в @Embeddedable
и один раз для, например, @ManyToOne
, где @ManyToOne
должен быть доступен только для чтения (@PrimaryKeyJoinColumn
), t имеет один столбец, заданный двумя переменными (возможные конфликты).
Поэтому вам нужно установить свой FK с помощью простого типа в @Embeddedable
.
На другом сайте с использованием @IdClass
эту ситуацию можно обрабатывать гораздо проще, как показано в Первичные ключи через отношения OneToOne и ManyToOne:
Пример JPA 2.0 Многопользовательская аннотация
...
@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;
}
}
Ответ 4
Существует три стратегии использования составного первичного ключа:
- Отметьте его как
@Embeddable
и добавьте в свой класс сущности нормальное свойство для него, помеченное @Id
.
- Добавьте к классу сущности нормальное свойство для него, помеченное
@EmbeddedId
.
- Добавить свойства в класс сущности для всех его полей, пометить их
@Id
и пометить класс сущности @IdClass
, предоставив класс вашего основного класса ключей.
Использование @Id
с классом, помеченным как @Embeddable
, является наиболее естественным подходом. Тег @Embeddable
может использоваться для вложенных значений не первичного ключа. Он позволяет обрабатывать составной первичный ключ как одно свойство и позволяет повторно использовать класс @Embeddable
в других таблицах.
Следующим наиболее естественным подходом является использование тега @EmbeddedId
. Здесь класс первичного ключа не может использоваться в других таблицах, поскольку он не является объектом @Embeddable
, но он позволяет нам рассматривать ключ как
единственный атрибут некоторого класса.
Наконец, использование аннотаций @IdClass
и @Id
позволяет нам отображать составной класс первичного ключа, используя свойства самого объекта, соответствующие именам свойств в классе первичного ключа. Имена должны соответствовать (нет механизма для переопределения этого), а класс первичного ключа должен выполнять те же обязательства, что и в отношении двух других методов. Единственным преимуществом этого подхода является его способность "скрыть" использование класса первичного ключа из интерфейса охватывающего объекта. Аннотация @IdClass
принимает параметр значения типа Class, который должен быть классом, который будет использоваться в качестве составного первичного ключа. Поля, соответствующие свойствам класса первичного ключа, которые должны использоваться, должны быть аннотированы с помощью @Id
.
Ссылка: http://www.apress.com/us/book/9781430228509
Ответ 5
Я думаю, что главным преимуществом является то, что мы могли бы использовать @GeneratedValue
для id при использовании @IdClass
? Я уверен, что мы не можем использовать @GeneratedValue
для @EmbeddedId
.
Ответ 6
Композитный ключ не должен иметь свойство @Id
, когда используется @EmbeddedId
.