2017-01-13 22 views
2

У меня есть два объекта PointOfInterest (называемый здесь POI) и его адрес. Я хочу определить одно к одному двунаправленное сопоставление с общим первичным ключом между ними, с POI как объект владельца. Я использую postgreSQL DB, таблица POI имеет POIId как PK, сгенерированный генератором последовательности, определенным в БД. Таблица адресов имеет столбец POIId, который является таблицей адресов PK, а также столбец POII таблицы FK для POI, а также другие столбцы.Hibernate @OneToOne с общим основным ключом (двунаправленный). Зависимый объект не сохраняется в БД.

**PointOfInterest.java** 

@Entity 
@Table(name = "\"POI\"") 
public class PointOfInterest implements Serializable { 
    private static final long serialVersionUID = -5406785879200149642L; 

    @Id 
    @Column(name="\"POIId\"", nullable=false) 
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="poi_seq_poiid_generator") 
    @SequenceGenerator(name = "poi_seq_poiid_generator", sequenceName = "poi_seq_poiid", allocationSize=1) 
    private Long poiId; 

    @OneToOne(mappedBy = "poi",cascade = CascadeType.PERSIST) 
    private Address address; 

    //Other fields 

----------------------------------------------------------------- 
    **Address.java** 
    @Entity 
    @Table(name="\"Address\"") 
    public class Address implements Serializable{ 

     private static final long serialVersionUID = -7146133528411371107L; 

     @Id 
     @GeneratedValue(generator="sharedPrimaryKeyGenerator") 
     @GenericGenerator(name="sharedPrimaryKeyGenerator",strategy="foreign",parameters = @Parameter(name="property", value="poi")) 
     @Column(name="\"POIId\"") 
     private Long poiId; 

     @OneToOne 
     @PrimaryKeyJoinColumn 
     private PointOfInterest poi; 

Перед сохранением объекта POI с использованием session.saveOrUpdate (poi). Я создаю экземпляр и задаю все другие свойства объекта POI. Затем получите объект Address из отдельного метода в моей логике и сделайте что-нибудь вроде.

PointOfInterest poi = methodCallToGetPOI(); 
Address address = methodCallToGetAddress(); 

poi.setAddress(address); 
address.setPOI(poi); 

//Send POI object to DB layer to an appropriate method which does: 

session.saveOrUpdate(poi); 
session.flush(); 

Когда я вижу сгенерирован запрос, я вижу что-то вроде этого:

Hibernate: 
    select 
     nextval ('poi_seq_poiid') 

Hibernate: 
    insert 
    into 
     "POI" 
     ("CreatedBy", "CreatedTime", "LocationGeographic", "ModifiedBy", "ModifiedTime", "Name", "POICode", "Radius", "POIType", "POIId") 
    values 
     (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 

Таким образом, очевидно, спящий режим не делает оператор вставки в таблицу адресов. Я искал всюду в Интернете и сравнивал мои сопоставления, они кажутся правильными. Однако ни одна строка не вставлена ​​в таблицу адресов. Когда я отлаживаю поток, я обнаружил, что объект адреса создается и заполняется. Пожалуйста, помогите мне разобраться, почему это так. Единственная причина, по которой я могу думать об этом, что я использую генератор последовательности, а во всех примерах и фрагментах кода в Интернете все используют стратегию генерации генерации гиберната, значит, из-за этого? Я не могу использовать ключ автогенератора, я должен использовать только свою последовательность БД. Если эти аннотации не будут работать, любезно предложите альтернативу.

Я использую Spring и Hibernate с пружинным Framework версии 4.0.5.RELEASE и сессионными фабриками, полученных из org.springframework.orm.hibernate4.LocalSessionFactoryBean и менеджером транзакций, полученная из org.springframework.orm.hibernate4.HibernateTransactionManager.

ответ

1

Вы также не хотите генерировать PK на адресе (даже с помощью специального генератора).

Поскольку эти два объекта совместно используют ПК, генерация может произойти только один раз. Тогда отображение должно отвечать за заполнение как POI_ID, так и ADDRESS_ID с тем же значением.

Странная вещь, @PrimaryKeyJoinColumn больше не работает на Hibernate 5.2.2, но здесь эквивалентное отображение:

@Entity 
@Table(name = "POI") 
public class PointOfInterest implements Serializable 
{ 
    private static final long serialVersionUID = 1L; 

    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "poi_seq_poiid_generator") 
    @SequenceGenerator(name = "poi_seq_poiid_generator", sequenceName = "poi_seq_poiid", allocationSize = 1) 
    @Column(name = "POI_ID") 
    private Long id; 

    @OneToOne(mappedBy = "poi", cascade = CascadeType.ALL, orphanRemoval = true) 
    private Address address; 

    @Column 
    private String name; 

    ... 
} 

@Entity 
@Table(name = "Address") 
public class Address implements Serializable 
{ 
    private static final long serialVersionUID = 1L; 

    @Id 
    @OneToOne 
    @JoinColumn(name = "ADDRESS_ID") 
    private PointOfInterest poi; 

    @Column 
    private String name; 

    ... 
} 

Использование поколения Hibernate DDL, это результирующий SQL:

create table Address (name varchar(255), ADDRESS_ID bigint not null, primary key (ADDRESS_ID)) ENGINE=InnoDB 
create table POI (POI_ID bigint not null, name varchar(255), primary key (POI_ID)) ENGINE=InnoDB 
alter table Address add constraint FK_Address_ADDRESS_ID foreign key (ADDRESS_ID) references POI (POI_ID) 
+0

Привет, Спасибо за ваш ответ, но проблема не решена. Только объект PointOfItnerest заполняется. Не могли бы вы также объяснить, почему генератор adhoc не требуется? – nbnb

+0

Вы правы, я тестировал его на Hibernate 5.2.2, и он больше не работает. см. обновление для альтернативного сопоставления, которое заботится о ссылке ID. Обратите внимание, что я тестировал только генерацию DDL, не знаю, будет ли идентификатор адреса автоматически заполняться во время выполнения (но он должен). –

+0

Спасибо за редактирование :) Я на самом деле заработал. Просто изменил cascadeType на cascadeType.ALL и вдруг строки адреса вставляются. – nbnb

0

После нескольких часов экспериментов с кодом выяснилось, что это одно-одно двунаправленное сопоставление, похоже, работает только тогда, когда указан параметр cascade = cascadeType.ALL. Я не хотел этого, потому что, сохраняя POI, поле адреса заполняется из внутренних вызовов API, которые основаны на географических точках POI. Итак, когда кто-то пытается обновить POI, они никогда не узнают его адрес и поэтому он будет null. Как только произойдет обновление, это приведет к тому, что строка таблицы адресов будет равна null для этой конкретной POI. Но сейчас он будет работать. Тем не менее, по-прежнему не уверен, почему для такого отображения обязательно указывать cascadeType.ALL. Конечно, это логично, но не объясняет, почему cascadeType.PERSIST не будет работать.

Кроме того, сопоставления, которые я использовал, такие как @GenericGenerator, являются спящими, и поэтому этот код выполняет сопоставление только в режиме спящего режима, а не в JPA.Кроме того, @GenericGenerator - это просто средство для того, чтобы сообщать в спящий режим, что он должен заполнить Идентификатор адреса с идентификатором, который был сгенерирован для POI по его последовательности.

 Смежные вопросы

  • Нет связанных вопросов^_^