Hibernate: где insertable = false, updatable = false принадлежат составным созвездиям первичных ключей с участием внешних ключей?
при реализации составных первичных ключей в Hibernate или других ORMs есть до трех мест, где можно поместить insertable = false, updatable = false в составные созвездия первичных ключей, которые используют идентифицирующие отношения (FKs, которые являются частью PK):
- в составную аннотацию @Column класса PK (только @ Embeddable classes) или
- в аннотацию @JoinColumn/s Ассоциации класса сущностей или
- В класса сущностей резервные аннотация @Column свойства PK (только классы@IdClass)
третий-единственный способ сделать с @IdClass и JPA 1.0 AFAIK. Смотри http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Primary_Keys_through_OneToOne_Relationships - ... Я буду рассматривать только случаи 1. и 2.
Q: Какой способ является предпочтительным местом для размещения "insertable = false, updatable = false" в целом?
Я испытал проблемы с Hibernate по этому вопросу. Например, Hibernate 3.5.x будет жаловаться на таблицу Zips
CREATE TABLE Zips
(
country_code CHAR(2),
code VARCHAR(10),
PRIMARY KEY (country_code, code),
FOREIGN KEY (country_code) REFERENCES Countries (iso_code)
)
С:
org.hibernate.MappingException: Repeated column in mapping for entity: com.kawoolutions.bbstats.model.Zip column: country_code (should be mapped with insert="false" update="false")
org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:676)
org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:698)
...
как вы можете видеть, столбец country_code - это PK и FK. Вот его классы:
класса сущности:
@Entity
@Table(name = "Zips")
public class Zip implements Serializable
{
@EmbeddedId
private ZipId id;
@ManyToOne
@JoinColumn(name = "country_code", referencedColumnName = "iso_code")
private Country country = null;
...
}
составной класс ПК:
@Embeddable
public class ZipId implements Serializable
{
@Column(name = "country_code", insertable = false, updatable = false)
private String countryCode;
@Column(name = "code")
private String code;
...
}
при вставке insertable = false, updatable = false в @JoinColumn ассоциации классов сущностей все исключения исчезают и все работает нормально. Однако я не вижу, почему приведенный выше код не должен работать. Возможно, у Hibernate проблемы с этим. Является ли описанная ошибка гибернации, поскольку она, похоже, не оценивает столбец @"insertable = false, updatable = false"?
по сути, каков стандартный способ JPA, лучшая практика или предпочтение, где поставить "insertable = false, updatable = false"?
2 ответов
позвольте мне ответить пошаговые.
1. Когда вы нужны вставные = значение false, обновляемые = false`в?
давайте посмотрим на приведенное ниже отображение,
public class Zip {
@ManyToOne
@JoinColumn(name = "country_code", referencedColumnName = "iso_code")
private Country country = null
@Column(name = "country_code")
private String countryCode;
}
здесь мы имеем в виду один и тот же столбец в таблице, используя два разных свойства. В приведенном ниже коде
Zip z = new Zip();
z.setCountry(getCountry("US"));
z.setCountryCode("IN");
saveZip(z);
что здесь будет делать hibernate??
чтобы предотвратить такого рода несоответствия, hibernate просит вас указать точку обновления кораблей отношений. Что означает вы можете ссылаться на тот же столбец в таблице n
количество раз, но только один из них может быть использован для обновления и все остальные будут читать только.
2. Почему hibernate жалуется на ваше отображение?
в своем Zip
class вы имеете в виду встроенный id class ZipId
это снова содержит код страны. Как и в приведенном выше сценарии, теперь у вас есть возможность обновить counry_code
колонка из двух мест. Следовательно, ошибка данный hibernate является правильным.
3. Как это исправить в вашем случае?
нет. В идеале вы хотите свой ZipId
класс для создания идентификатора, поэтому вы не должны добавлять insertable = false, updatable = false
в countryCode внутри ZipId
. Таким образом, исправление, как показано ниже, изменяет country
отображение в Zip
класс, как показано ниже
@ManyToOne
@JoinColumn(name = "country_code", referencedColumnName = "iso_code",
insertable = false, updatable = false)
private Country country;
надеюсь, это поможет вашему пониманию.
вы также можете решить эту проблему с помощью @PrimaryKeyJoinColumn
Примечание . Аннотация PrimaryKeyJoinColumn указывает столбец первичного ключа, который используется в качестве внешнего ключа для соединения с другой таблицей.
аннотация PrimaryKeyJoinColumn используется для присоединения первичной таблицы подкласса сущности в стратегии объединенного отображения к первичной таблице его суперкласса; она используется в аннотации SecondaryTable для присоединения вторичной таблицы к первичной таблице; и она может быть использована в Отображение OneToOne, в котором первичный ключ объекта ссылки используется в качестве внешнего ключа для объекта ссылки. Если для подкласса в стратегии объединенного сопоставления не задана аннотация PrimaryKeyJoinColumn, предполагается, что столбцы внешнего ключа имеют те же имена, что и столбцы первичного ключа первичной таблицы суперкласса.