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

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

  1. в составную аннотацию @Column класса PK (только @ Embeddable classes) или
  2. в аннотацию @JoinColumn/s Ассоциации класса сущностей или
  3. В класса сущностей резервные аннотация @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, предполагается, что столбцы внешнего ключа имеют те же имена, что и столбцы первичного ключа первичной таблицы суперкласса.