В этом уроке речь пойдет о связях между таблицами базы данных на уровне Entity.
Теоретический материал
Что такое связь между Entity?
Entity – это сущность которая является отображением в базе данных. Связь между Entity – это зависимость одной сущности от другой. Очень часто используются они в построении больших БД.
Теперь рассмотрим какие есть виды связей
Допустим есть сущность A и сущность B как сделать между ними различные типы связей:
1. OneToOne – один к одному
На рисунку выше видно что есть две сущности Автор и Книга. Так как сущности имеют связь OneToOne, то с сущности Книга можно получить Автора этой книги, а с сущности Автор можно получить его книгу.
2. OneToMany – один ко многому
3. ManyToOne – много к одному
OneToMany и ManyToOne обычно применяет вместе, что это дает?
Со стороны Автора мы сможем получить список книг которые он написал – это связь OneToMany, а со стороны Книги мы можем получить автора который написал данную книгу – это связь ManyToOne.
4. ManyToMany – много ко многому
В этой связи со стороны Автора мы можем получить все книги автора, а со стороны Книги мы можем получить список авторов, которые написали книгу.
Реализация
Теперь реализуем все выше рассмотренные виды связей.
Для дальнейших примеров нам нужно реализовать сущность Автор и Книга.
Создаем класс Author.java, который будет отображать сущность Автор.
package com.devcolibri.admin.entity; import javax.persistence.*; @Entity @Table(name = "author") public class Author { @Id private Integer id; @Column(name = "name") private String name; @Column(name = "last_name") private String lastName; public Author() { } 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 String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } }
Создаем класс Book.java, который будет отображать сущность Книга.
package com.devcolibri.admin.entity; import javax.persistence.*; @Entity @Table(name = "book") public class Book { @Id Integer id; @Column(name = "name") private String name; public Book() { } 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; } }
Обязательно должны быть Getter & Setter для того чтобы JPA мог инициализировать данные поля.
OneToOne
В сущность Author добавляем следующее:
@OneToOne(optional = false) @JoinColumn(name="book_id", unique = true, nullable = false, updatable = false) private Book book; public Book getBook() { return book; } public void setBook(Book book) { this.book = book; }
а в сущность Book:
@OneToOne(optional = false, mappedBy="book") public Author author; public Author getAuthor() { return author; } public void setAuthor(Author author) { this.author = author; }
Обратите внимание на mappedBy, он указывает на имя атрибута сущности Author для связи с ним.
OneToMany и ManyToOne
В сущность Author добавляем следующее:
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.MERGE, CascadeType.PERSIST}) @JoinColumn(name = "book_id", nullable = false) private Book book; public Book getBook() { return book; } public void setBook(Book book) { this.book = book; }
а в сущность Book:
@OneToMany(fetch = FetchType.EAGER, mappedBy = "book") private Set<Author> users; public Set<Author> getUsers() { return users; } public void setUsers(Set<Author> users) { this.users = users; }
ManyToMany
В сущность Author добавляем следующее:
@ManyToMany @JoinTable(name="author_book", joinColumns = @JoinColumn(name="author_id", referencedColumnName="id"), inverseJoinColumns = @JoinColumn(name="book_id", referencedColumnName="id") ) private Set<Book> books; public Set<Book> getBooks() { return books; } public void setBooks(Set<Book> books) { this.books = books; }
а в сущность Book:
@ManyToMany(fetch = FetchType.EAGER, mappedBy = "books") private Set<Author> users; public Set<Author> getUsers() { return users; } public void setUsers(Set<Author> users) { this.users = users; }
При такой связи будет получена новая промежуточная таблица:
CascadeType
Определяет набор каскадных операций, которые распространяются на соответствующие сущности:
cascade=ALL – на все операции
cascade={PERSIST, MERGE, REMOVE, REFRESH, DETACH} – на определенные операции, те что есть в перечислении будут учитываться.
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.MERGE, CascadeType.PERSIST}) @JoinColumn(name = "book_id", nullable = false) private Book book;
В зависимости от cascade будет либо учитываться связь между сущностями для выполнения операции, либо нет.
FetchType
Определение стратегии для извлечения данных из базы данных.
EAGER – стратегия, которая предусматривает получение полной связи между сущностями, и последующих обращениях к связям не будет выполнять запрос на получение данных, так как данные изначально были получены полностью.
@OneToMany(fetch = FetchType.EAGER, mappedBy = "book") private Set<Author> users;
LAZY – стратегия, которая не предусматривает получение полной связи сущностей, и при первом обращении к связи будет выполнятся запрос на получение данных с БД.
@OneToMany(fetch = FetchType.LAZY, mappedBy = "book") private Set<Author> users;
ПОХОЖИЕ ПУБЛИКАЦИИ
- None Found
14 комментариев к статье "Как связать Entity в JPA?"
Добавить комментарий
Для отправки комментария вам необходимо авторизоваться.
Здорово конечно. Смущают поля вроде book_id в которых непонятно что хранится и в какой таблице они находятся.
book_id хранит id книги с таблицы book для связи.
смущает еще следующее (возможно, просто не вникла в суть я)
раздел OneToMany и ManyToOne:
1) Set users – users ? почему пользователи(читатели), если речь идет об авторах
2) в коде сущности Book та же строка: private Set users, в коде сущности Author: private Book book;. так в данном примере у книги много авторов, и автор пишет одну книгу, или все-таки это ошибка и должно быть наоборот?
у одной книге может быть несколько авторов, Ну с именами переменых можно было бы и подумать :)
про то что у книги несколько авторов это несомненно, но в данном случае описывалась связь один-ко многим. Один – со стороны автора (судя по вступлению к статье и схеме связей), а в коде один- со стороны книги, это слегка путает неопытного читателя
Здравствуйте! Спасибо за такой мануал. Он мне здорово помог.
Но здесь @ManyToMany(fetch = FetchType.EAGER, mappedBy = “book”) у вас ошыбка, вместо “book” должно быть “books”, иначе не работает.
Спасибо за исправление, пофиксил :)
Добрый вечер. Спасибо за статью. Но был бы рад увидеть продолжение в виде Дао класса, где мы добавляем поле в эти таблицы.
В случае связи oneToMany, хочу добавить значения в таблицу автор и несколько книг. При этом у книг должен быть айди автора.
Как это сделать? Как написать метод правильно? em.persist(author); добавить ведь только автора, есть ли метод у ентити менеджера, который закинет скопом в две таблицы данные, при этом с одной таблице передаст другой айди автора?
Пс. из любопытсва, этот сайт вордпресс или сами писали?))
Здравствуйте. Вы должны сохранить объект, em.merge он вернет вам тотже объект но уже с id дальше вы его проставляете set в тот объект который от него зависит и сохраняете, таким образом он ссылается на него. Ну а пачкой сохранить не совсем корректно :) Да на вордпресе, ну совсем скоро мы перезагрузимся, на новую версию которую мы пишем на Java EE.
Народ, кто нибудь объясните, неужели в EJB 3 нет возможности вывести список, содержащий поля нескольких связных таблиц? Я всё это читаю и у меня складывается впечатление что в простом примере с 3я таблицами 1) сотрудник(ид,фио и должность) 2) телефон(ид_сотрудника и номер) 3) паспорт(поля паспорта) при наличие сущностей имея задачей вывести перечень сотрудников с номерами телефонов и адресами прописки я должен дополнительно к сессионному бину создать ещё свой класс представление, содержащий все необходимые для вывода поля, затем итеративно заполнить вновь созданный список и только после этого могу его вывести на экран в фасаде?
А не перепутали ли вы связи в диаграмме после слов “При такой связи будет получена новая промежуточная таблица:” ?
Добрый день! Спасибо большое за статью. Только Все равно абсолютно не ясно что за поле @JoinColumn(name = “book_id”) ? Можно ли детально объяснить? Можно пример и схему таблиц? В Ентити books нет поля book_id, как его тогда установить? Спасибо
Результат запроса по указанной ссылке.
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Nov 29 10:11:51 EST 2016
There was an unexpected error (type=Internal Server Error, status=500).
I/O error on GET request for “http://localhost:9100/server/v1/hub/java”: Connection refused; nested exception is java.net.ConnectException: Connection refused
не переходит по ссылке, говорит 502 ошибка