Аннотация HIbernate one-to-one не генерирует GerericGenerator внешнего ключа в зависимой таблице

#java #spring #hibernate #postgresql #jpa-2.1

#java #spring #спящий режим #postgresql #jpa-2.1

Вопрос:

Я пытаюсь создать одно-единственное отношение между пользователем и таблицей аутентификации. Проблема в том, что при создании таблицы DB «Auth» я не вижу внешнего ключа в таблице аутентификации, который должен ссылаться на Person. Цель состоит в том, чтобы таблица аутентификации использовала тот же первичный ключ таблицы Person.

  @MappedSuperclass
 public abstract class DomainBase {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE) 
    private Long id;

    @Version
    @Column(name="OPLOCK")
    private Integer version;
 }


 @Entity
 @Table(name = "person")  
 public class Person extends DomainBase {
        @OneToOne(cascade=CascadeType.ALL)
            @JoinColumn(name="auth_id")
        private Auth auth;
 }


 @Entity
 public class Auth {
    @Id
    @GeneratedValue(generator="foreign")
    @GenericGenerator(name="foreign", strategy = "foreign", parameters={
      @Parameter(name="property", value="person")
    })
    @Column(name="person_id")
    private int personId;
    ---------------------------------

    @OneToOne(cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn 
    private Person person;
 }
  

Мои скрипты базы данных после генерации гибернации DB.

  CREATE TABLE auth
 (
   person_id integer NOT NULL,
   activate boolean,
   activationid character varying(255),
   last_login_attempt_date timestamp without time zone,
   last_login_attempt_timezone character varying(255),
   last_login_date timestamp without time zone,
   last_login_timezone character varying(255),
   nonlocked boolean,
   num_login_attempts integer,
   CONSTRAINT auth_pkey PRIMARY KEY (person_id),
   CONSTRAINT uk_d68auh3xsosyrjw3vmwseawvt UNIQUE (activationid)
 )
 WITH (
   OIDS=FALSE
 );
 ALTER TABLE auth
   OWNER TO postgres;
  

Ответ №1:

Похоже, проблема в том, что вы дважды объявляете аннотацию @OneToOne между таблицей «person» и таблицей «auth», не указывая связь между ними. Взгляните на документацию hibernate, в пункте 2.2.5.1, есть несколько примеров использования взаимно однозначной ассоциации.

Для меня лучший способ — настроить ассоциацию в одной таблице, той, в которой объявлен столбец foreing key, и использовать mappedBy параметр в другом объекте. В вашем коде это будет :

  @Entity
 @Table(name = "person")  
 public class Person extends DomainBase {
     @OneToOne(cascade=CascadeType.ALL)
     @JoinColumn(name="auth_id")
     private Auth auth;
 }


 @Entity
 public class Auth {
     @Id
     @GeneratedValue(generator="foreign")
     @GenericGenerator(name="foreign", strategy = "foreign", parameters={
         @Parameter(name="property", value="person")
     })
     @Column(name="person_id")
     private int personId;

     @OneToOne(mappedBy = "auth")
     private Person person;
....
 }
  

Это второй пример в документации hibernate, представленный сразу после предложения «В следующем примере связанные объекты связаны через явный столбец внешнего ключа». Я протестировал этот код, и появился столбец «auth_id».

Комментарии:

1. документация по гибернации отсутствует. Что превращает onetoone в общий первичный ключ? Из документов, которые вы показали, я не вижу, что заставляет это быть. Можете ли вы объяснить?

2. Под «общими первичными ключами» я просто подразумеваю использование идентификатора таблицы как внешнего ключа в другой таблице, чтобы разрешить связь между ними. Я не должен был использовать термин «общий». Я редактирую свой ответ

3. При такой конфигурации я получаю эту ошибку -> попытка присвоить идентификатор из нулевого свойства один-к-одному [XXXXX.domains.Auth.person] при попытке перейти по этой ссылке

4. Когда вы устанавливаете аутентификацию для пользователя, у аутентификации должен быть идентификатор. Чтобы реализовать это, создайте auth, сохраните его, получите и затем свяжите его с объектом person . В конкретных терминах добавьте Auth authSaved = this.authRepository.save(auth) между строкой 3 и строкой 4. Возможно, вам нужно изменить стратегию сгенерированного значения для идентификатора аутентификации. Если это так, используйте @GeneratedValue(strategy = GenerationType.AUTO) вместо обоих @GeneratedValue и @GenericGenerator аннотаций, это должно работать.

5. думал, что это было целью использования общего первичного ключа. Как и в случае, если владелец поделится своим сохраненным первичным ключом с зависимым, а взамен зависимый будет использовать это значение в качестве собственного первичного ключа.