Статьи

Двунаправленная ассоциация первичного ключа @OneToOne

Пришло время продолжить статьи о Hibernate. Последний был посвящен однонаправленной ассоциации @OneToOne . Итак, сегодня я покажу вам, как получить двунаправленную связь первичного ключа @OneTonOne . Пример из этого урока основан на предыдущей статье. Давайте начнем.

Я буду работать с теми же таблицами, которые я создал ранее. Чтобы установить двунаправленную связь один к одному, мне нужно обновить два POJO и способ сохранения процесса. Давайте рассмотрим новую версию класса Author:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import javax.persistence.*;
 
@Entity
@Table(name='authors')
public class Author {
 
    @Id
    @GeneratedValue
    private Integer id;
 
    private String name;
 
    @OneToOne(mappedBy='author', cascade=CascadeType.ALL)
    private Biography biography;
 
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public Biography getBiography() {
        return biography;
    }
 
    public void setBiography(Biography biography) {
        this.biography = biography;
    }
 
}

Изменения минимальны. Я только что удалил @PrimaryKeyJoinColumn из поля биографии. В двунаправленном объединении появляется две стороны объединения — владеющая и обратная . Для двунаправленных отношений один к одному сторона-владелец соответствует стороне, которая содержит соответствующий внешний ключ. В нашем случае владельцем является класс Author. Вперед.

Цитата из спецификации JPA 2:

Обратная сторона двунаправленного отношения должна ссылаться на свою собственную сторону с помощью элемента mappedBy аннотации OneToOne, OneToMany или ManyToMany. Элемент mappedBy обозначает свойство или поле в объекте, который является владельцем отношения.

Обратной стороной в этом примере является класс Biography. Это требует более существенных изменений по сравнению с классом Author.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import javax.persistence.*;
 
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
 
@Entity
@Table(name='biographies')
public class Biography {
 
    @Id
    @Column(name='author_id')
    @GeneratedValue(generator='gen')
    @GenericGenerator(name='gen', strategy='foreign',
    parameters=@Parameter(name='property', value='author'))
    private Integer authorId;
 
    private String information;
 
    @OneToOne
    @PrimaryKeyJoinColumn
    private Author author;
 
    public Author getAuthor() {
        return author;
    }
 
    public void setAuthor(Author author) {
        this.author = author;
    }
 
    public Integer getAuthorId() {
        return authorId;
    }
 
    public void setAuthorId(Integer authorId) {
        this.authorId = authorId;
    }
 
    public String getInformation() {
        return information;
    }
 
    public void setInformation(String information) {
        this.information = information;
    }  
}

Первым важным моментом является оформление поля authorId дополнительными аннотациями.

1
2
3
4
5
...
@GeneratedValue(generator='gen')
@GenericGenerator(name='gen', strategy='foreign',
parameters=@Parameter(name='property', value='author'))
...

В @GeneratedValue я указываю имя генератора («gen»), а в @GenericGenerator я определяю стратегию для генератора. Вторым важным моментом является добавление автора, зарегистрированного в классе, с соответствующими методами получения и установки.

1
2
3
4
5
...
    @OneToOne
    @PrimaryKeyJoinColumn
    private Author author;
...

Таким образом, мы получаем двунаправленную ассоциацию. Теперь мы можем получить доступ к автору из биографии и наоборот, поскольку оба объекта имеют ссылки друг на друга. Теперь процесс сохранения объектов должен быть обновлен:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
    public static void main(String[] args) {
 
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
        Session session = sessionFactory.openSession();
        session.beginTransaction();
 
        Author author = new Author();
        author.setName(' O. Henry');
 
        Biography biography = new Biography();
        biography.setInformation('William Sydney Porter  better known as O. Henry...');
 
        author.setBiography(biography);
        biography.setAuthor(author);
 
        session.save(author);
 
        session.getTransaction().commit();
 
        session.close();
 
    }
...

Обратите внимание, что теперь я не сохраняю свою сторону, пока не добавляю обратную сторону. Но вы можете видеть, что я установил биографию для автора, и в следующей строке я установил автора для биографии . Это основная цель двунаправленной ассоциации. Результат выполнения кода:

1
2
Hibernate: insert into authors (name) values (?)
Hibernate: insert into biographies (information, author_id) values (?, ?)

Ссылка: Двунаправленная ассоциация первичного ключа @OneToOne от нашего партнера по JCG Алекса Фрузенштейна в блоге заметок Фрузенштейна .