Подтвердить что ты не робот

Hibernate: где insertable = false, updatable = false принадлежит составным созвездиям первичных ключей с участием внешних ключей?

При реализации составных первичных ключей в Hibernate или других ORM существует до трех мест, где можно поставить insertable = false, updatable = false в составные созвездия первичных ключей, которые используют идентифицирующие отношения (FKs, которые являются частью PK):

  • В составный класс PK '@Column annotation (только классы @Embeddable) или
  • В ассоциацию сущностей класса @аннотация ассоциации JoinColumn/s или
  • В класс сущности класса избыточное свойство PK @Колонная аннотация (только классы @IdClass)

Третий - это единственный способ сделать это с помощью @IdClass и JPA 1.0 AFAIK. См. http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Primary_Keys_through_OneToOne_Relationships. Я рассмотрю только случаи 1. и 2.

В: Какой путь является предпочтительным местом для размещения "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;
...
}

Составной класс PK:

@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 возникли проблемы с этим. Является ли описанная ошибка Hibernate, поскольку она, похоже, не оценивает @Column "insertable = false, updatable = false" ?

В сущности, какой стандартный способ JPA, лучшая практика или предпочтение, где поставить "insertable = false, updatable = false" ?

4b9b3361

Ответ 1

Позвольте мне ответить шаг за шагом.

1. Когда вам нужно `insertable = false, updatable = 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"));
x.setCountryCode("IN");

saveZip(z);

Что здесь будет делать спящий режим?

Чтобы предотвратить такую ​​несогласованность, hibernate просит вас указать точку обновления отношений судов. Это означает, что вы можете ссылаться на один и тот же столбец в таблице n количество раз, но только один из них может быть использован для обновления, а все остальные будут прочитаны только.

2. Почему hibernate жалуется на ваше сопоставление?

В вашем классе Zip вы ссылаетесь на класс Embedded id ZipId, который снова содержит код страны. Как и в приведенном выше сценарии, теперь у вас есть возможность обновить столбец counry_code из двух мест. Следовательно, ошибка, заданная спящим состоянием, является правильной.

3. Как исправить это в вашем случае?

Нет. В идеале вы хотите, чтобы ваш класс ZipId сгенерировал идентификатор, поэтому вы не должны добавлять insertable = false, updatable = false в код страны внутри ZipId. Таким образом, исправление как ниже изменяет отображение country в вашем классе Zip, как показано ниже,

@ManyToOne
@JoinColumn(name = "country_code", referencedColumnName = "iso_code",
insertable =  false, updatable = false)
private Country country;

Надеюсь, это поможет вашему пониманию.

Ответ 2

Вы также можете решить эту проблему, используя аннотацию @PrimaryKeyJoinColumn. Аннотации PrimaryKeyJoinColumn задают столбец первичного ключа, который используется в качестве внешнего ключа для присоединения к другой таблице.

Аннотации PrimaryKeyJoinColumn используются для присоединения к первичной таблице подкласса объекта в стратегии сопоставления JOINED к первичной таблице его суперкласса; он используется в аннотации SecondaryTable для присоединения вторичной таблицы к первичной таблице; и он может использоваться в сопоставлении OneToOne, в котором первичный ключ ссылочного объекта используется в качестве внешнего ключа для ссылочного объекта. Если аннотация PrimaryKeyJoinColumn не указана для подкласса в стратегии сопоставления JOINED, предполагается, что столбцы внешнего ключа имеют те же имена, что и столбцы первичного ключа в первичной таблице суперкласса.