Гибернация: где вставка = ложь, возможность обновления = ложь относятся к составным группам первичных ключей с участием внешних ключей? - PullRequest
32 голосов
/ 08 сентября 2010

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

  1. В составную аннотацию класса PK '@Column (только для классов @Embeddable) или
  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.

В: Каким способом предпочтительнее в общем случае указать «вставляемый = ложный, обновляемый = ложный»?

У меня возникли проблемы с 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;
...
}

При помещении вставляемого = false, Updatable = false в класс сущности@JoinColumn ассоциации все исключения исчезают, и все работает нормально.Однако я не понимаю, почему приведенный выше код не должен работать.Возможно, у Hibernate возникли проблемы с этим.Является ли описанная ошибка Hibernate, поскольку она, похоже, не оценивает @Column "вставляемый = ложный, обновляемый = ложный"?

По сути, каков стандартный способ JPA, лучший метод или предпочтение, кудапоставить "вставляемый = ложь, обновляемый = ложь"?

Ответы [ 2 ]

66 голосов
/ 25 февраля 2012

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

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

saveZip(z);

Что будет здесь впадать в спячку ??

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

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

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

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

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

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

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

0 голосов
/ 20 февраля 2015

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

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

...