Статьи

Двунаправленная ассоциация @OneToMany / @ManyToOne

Одной из целей в программировании является представление моделей из реального мира. Очень часто приложению необходимо моделировать отношения между сущностями. В последней статье об ассоциациях Hibernate я описал правила настройки отношений «один к одному». Сегодня я собираюсь показать вам, как настроить двунаправленную связь « один ко многим » и « многие ко одному ». Этот пример будет основан на предыдущих уроках Hibernate .

В начале я должен сказать, что мой пример кода будет основан на простой ситуации. Давайте представим футбольную лигу. В каждой лиге есть команды, и в команде могут играть несколько игроков. Итак, итог таков: одна команда имеет много игроков, один игрок может играть за одну команду. Таким образом, мы получаем очевидные отношения « один ко многим » и « многие к одному ».

Я использую MySQL в качестве базы данных в этом примере. Вот скрипты для создания таблиц:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
CREATE TABLE `teams` (
  `id` int(6) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
 
CREATE TABLE `players` (
  `id` int(6) NOT NULL AUTO_INCREMENT,
  `lastname` varchar(20) NOT NULL,
  `team_id` int(6) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `player's team` (`team_id`),
  CONSTRAINT `player's team` FOREIGN KEY (`team_id`) REFERENCES `teams` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

Следующим шагом является создание POJO:

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
47
48
49
50
51
import java.util.Set;
 
import javax.persistence.*;
 
@Entity
@Table(name = 'teams')
public class Team {
 
    @Id
    @GeneratedValue
    private Integer id;
 
    private String name;
 
    @OneToMany(mappedBy='team', cascade=CascadeType.ALL)
    private Set
 
          players;
 
    public Team(String name) {
        this.name = name;
    }
 
    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 Set
 
           getPlayers() {
        return players;
    }
 
    public void setPlayers(Set
 
            players) {
        this.players = players;
    }
}

Я использовал @OneToMany, потому что в одной команде может быть много игроков. В следующем POJO ассоциация будет @ManyToOne, так как многие игроки могут играть за одну команду.

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
import javax.persistence.*;
 
@Entity
@Table(name = 'players')
public class Player {
 
    @Id
    @GeneratedValue
    private Integer id;
 
    private String lastname;
 
    @ManyToOne
    @JoinColumn(name = 'team_id')
    private Team team;
 
    public Player(String lastname) {
        this.lastname = lastname;
    }
 
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    public String getLastname() {
        return lastname;
    }
 
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }
 
    public Team getTeam() {
        return team;
    }
 
    public void setTeam(Team team) {
        this.team = team;
    }
}

Здесь я указываю столбец ( team_id ), который будет объединен со стороны владельца ( команды ). Обратите внимание, что я не объявляю поле team_id в POJO. Если мне нужно сменить команду для игрока, мне просто нужно использовать сеттер setTeam (Team team) .

После того, как POJO были объявлены, я могу продемонстрировать, как их сохранить:

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
...
    public static void main(String[] args) {
 
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
        Session session = sessionFactory.openSession();
        session.beginTransaction();
 
        Team team = new Team('Barcelona');
        Set
 
          players = new HashSet
 
          ();
 
        Player p1 = new Player('Messi');
        Player p2 = new Player('Xavi');
 
        p1.setTeam(team);
        p2.setTeam(team);
 
        players.add(p1);
        players.add(p2);
 
        team.setPlayers(players);
 
        session.save(team);
 
        session.getTransaction().commit();
 
        session.close();
 
    }
...

Результат выполнения кода:

Hibernate: вставить в команды (имя) значения (?)
Hibernate: вставить в игроков (фамилия, team_id) значения (?,?)
Hibernate: вставить в игроков (фамилия, team_id) значения (?,?)

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

Однонаправленные ассоциации сложнее запрашивать. В большом приложении почти все ассоциации должны быть ориентированы в обоих направлениях в запросах.

Ссылка: двунаправленная ассоциация @OneToMany / @ManyToOne от нашего партнера по JCG Алекса Фрузенштейна в блоге заметок Фрузенштейна .