Какую аннотацию мне следует использовать:@IdClass или @EmbeddedId

StackOverflow https://stackoverflow.com/questions/212350

Вопрос

Тот Самый JPA Спецификация (Java Persistence API) имеет 2 различных способа указания составных ключей сущности: @IdClass и @EmbeddedId.

Я использую обе аннотации для своих сопоставленных объектов, но это оказывается большой путаницей для людей, которые не очень хорошо знакомы с JPA.

Я хочу использовать только один способ указания составных ключей.Какой из них действительно лучший?Почему?

Это было полезно?

Решение

Я считаю, что @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 аннотация принимает значение параметра типа Class, который должен быть классом, который будет использоваться в качестве составного первичного ключа.Все поля, соответствующие свойствам используемого класса первичного ключа, должны быть снабжены комментариями @Id.

Ссылка: http://www.apress.com/us/book/9781430228509

Насколько я знаю, если ваш составной ПК содержит FK, проще и проще использовать @IdClass

С помощью @EmbeddedId вам нужно дважды определить отображение для вашего столбца FK, один раз в @Embeddedable и один раз как, например, @ManyToOne где @ManyToOne должен быть доступен только для чтения ( @PrimaryKeyJoinColumn ), поскольку нельзя задать один столбец в двух переменных (возможные конфликты).
Таким образом, вы должны установить свой FK, используя простой тип @Embeddedable .

На другом сайте, использующем @IdClass , эту ситуацию можно решить намного проще, как показано в Первичные ключи через отношения OneToOne и ManyToOne :

Пример JPA 2.0: аннотация id ManyToOne

...
@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

...
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 .

Составной ключ не должен иметь свойства @Id , когда используется @EmbeddedId .

С помощью EmbeddedId вы можете использовать предложение IN в HQL, например: FROM Entity WHERE id IN: ids , где id - это EmbeddedId, тогда как с IdClass трудно добиться того же результата, который вы захотите сделать что-то вроде FROM Entity WHERE idPartA =: idPartA0 AND idPartB =: idPartB0 .... ИЛИ idPartA =: idPartAN AND idPartB =: idPartBN

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top