How to map a composite key with JPA and Hibernate?
Как сопоставить составной ключ с JPA и гибернацией?
В этом коде показано, как сгенерировать класс Java для составного ключа (как создать составной ключ в hibernate):
create table Time( levelStation int(15) not null, src varchar(100) not null, dst varchar(100) not null, distance int(15) not null, price int(15) not null, confPathID int(15) not null, constraint ConfPath_fk foreign key(confPathID) references ConfPath(confPathID), primary key(levelStation, confPathID) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Переведено автоматически
Ответ 1
Для сопоставления составного ключа вы можете использовать EmbeddedIdилиIdClass аннотации. Я знаю, что этот вопрос не относится строго к JPA, но правила, определенные спецификацией, также применимы. Итак, вот они:
2.1.4 Первичные ключи и идентификация сущности
...
Составной первичный ключ должен соответствовать либо одному постоянному полю или свойству, либо набору таких полей или свойств, как описано ниже. Класс первичного ключа должен быть определен для представления составного первичного ключа. Составные первичные ключи обычно возникают при сопоставлении из устаревших баз данных, когда ключ базы данных состоит из нескольких столбцов. Аннотации EmbeddedId и IdClass используются для обозначения составных первичных ключей. Смотрите разделы 9.1.14 и 9.1.15.
...
Для составных первичных ключей применяются следующие правила:
Класс первичного ключа должен быть открытым и должен иметь открытый конструктор без аргументов.
Если используется доступ на основе свойств, свойства класса первичного ключа должны быть общедоступными или защищенными.
Класс первичного ключа должен быть serializable.
Класс первичного ключа должен определять equals и hashCode методы. Семантика равенства значений для этих методов должна соответствовать равенству базы данных для типов баз данных, которым сопоставляется ключ.
Составной первичный ключ должен быть либо представлен и сопоставлен как встраиваемый класс (см. Раздел 9.1.14, “Аннотация EmbeddedId”), либо должен быть представлен и сопоставлен с несколькими полями или свойствами класса entity (см. Раздел 9.1.15, “Аннотация IdClass”).
Если класс составного первичного ключа сопоставлен нескольким полям или свойствам класса entity, имена полей или свойств первичного ключа в классе primary key и в классе entity должны соответствовать и их типы должны быть одинаковыми.
С помощью IdClass
Класс для составного первичного ключа может выглядеть следующим образом (может быть статическим внутренним классом):
В @EmbeddedId аннотации класс PK сопоставляется с таблицей PK.
Различия:
С точки зрения физической модели различий нет
@EmbeddedId каким-то образом более четко сообщается, что ключ является составным ключом, и IMO имеет смысл когда объединенный pk либо сам по себе является значимой сущностью, либо повторно используется в вашем коде.
@IdClassполезно указать, что некоторая комбинация полей уникальна, но они не имеют особого значения.
Они также влияют на способ написания запросов (делая их более или менее подробными):
с IdClass
select t.levelStation from Time t
с EmbeddedId
select t.timePK.levelStation from Time t
Ссылки
Спецификация JPA 1.0
Раздел 2.1.4 "Первичные ключи и идентификация сущности"
Phone Сущность, которая имеет @ManyToOne ассоциацию с Employee, должна ссылаться на составной идентификатор из родительского класса с помощью двух @JoinColumnсопоставлений:
Класс первичного ключа должен определять методы equals и hashCode
При реализации equals вы должны использовать instanceof, чтобы разрешить сравнение с подклассами. Если Hibernate lazy загружает отношение "один к одному" или "многие к одному", у вас будет прокси для класса вместо обычного класса. Прокси - это подкласс. Сравнение имен классов завершится неудачей. Более технически: вы должны следовать принципу подстановки Liskows и игнорировать симметричность.
Следующая ошибка заключается в использовании чего-то вроде name.equals(that.name) вместо name.equals(это.getName()). Первый завершится ошибкой, если это прокси.