Бесплатный курс по Java: от основ до продвинутого уровня
Настройка связи Многие-ко-Многим в Hibernate приложении
Теперь настроим в нашем приложении связь Многие-ко-Многим.
Пусть теперь в нашем приложении будет еще одна новая таблица – "Издательство".
Эта таблица будет связана с ранее созданной таблицей "Книги автора".
Любая книжка может быть напечатана несколькими издательствами и любое издательство может печатать какие-угодно книги.
То есть связь многие книги ко многим издательствам.
Ясное дело, при удалении издательства из таблицы publisherне должны удаляться связанные с этим издательством книги в таблице author_books, поскольку эти книги могут быть связаны и с другими издательствами.
И наоборот тоже – удаление книги не должно приводить к удалению связанных с ней издательств.
Поэтому и в классе таблицы publisher и в классе таблицы author_booksнеобходимо исключить CascadeType=REMOVE.
Сделаем это.
Создадим теперь с помощью sql запроса таблицу publisherв которой будут храниться издательства.
Кто знает базы данных должен знать, что связь многие ко многим между двумя таблицами реализуется с помощью промежуточной таблицы, где есть два столбца – id издательства и id книги. Создадим эту таблицу.
Теперь создадим класс созданной только что таблицы publisher. И настроим связь Многие-ко-Многиммежду этим классом и классом AuthorBooks через промежуточную таблицу.
package HibernateApps;
import java.util.ArrayList;
import javax.persistence.*;
@Entity
@Table(name = “publisher”)
public class Publisher {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name=”id”)
private int id;
@Column(name=”name”)
private String publisherName;
//Теперь используем аннотацию
//@ManyToMany (Многие-ко-многим).
//многие Publisher ко многим AuthorBooks.
//Важно убрать CascadeType.REMOVE чтобы
//при удалении из БД какой-то из книги
//не удалялись из БД издательства
@ManyToMany(cascade = {CascadeType.DETACH,
CascadeType.REFRESH,
CascadeType.PERSIST,
CascadeType.MERGE})
//Теперь настраиваем связи таблицы publisher
//с таблицей author_books через промежуточную
//таблицу author_books_publisher.
@JoinTable(
Имя промежуточной таблицы.
name = “authours_books_publisher”,
//Указываем название атрибута
//промежуточной таблицы в котором
//хранятся идентификаторы строк
//из таблицы publisher.
joinColumns=@JoinColumn(name=”publisher_id”),
//Указываем название атрибута
//промежуточной таблицы в котором
//хранятся идентификаторы строк
//из таблицы author_books.
inverseJoinColumns=@JoinColumn(name=”authorbook_id”))
private List authorbook;
public Publisher() {
}
public Publisher(String publisherName) {
this.publisherName = publisherName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getPublisherName() {
return publisherName;
}
public void setPublisherName(
String publisherName) {
this.publisherName = publisherName;
}
public List getAuthorbook() {
return authorbook;
}
public void setAuthorbook(
List authorbook) {
this.authorbook = authorbook;
}
//Для связывания объекта книги
//с объектом издательства просто
//добавляем объект книги в List
//объекта издательства. Тогда при
//добавлении в БД издательства, через
//объект издательства добавляются в БД
//и книги находящиеся в List
//в этом объекте издательства.
public void setOneBook(
AuthorBooks authorbook){
if (this.authorbook==null) {
this.authorbook = new ArrayList<>();
}
this.authorbook.add(authorbook);
}
@Override
public String toString() {
return “Publisher [id=” + id
+ “, publisherName=”
+ publisherName
+ “, authorbook=”
+ authorbook + “]”;
}
}
Теперь в классе таблицы author_books настроим связь Многие-ко-Многиммежду этим классом и классом Publisher также через промежуточную таблицу.
Связь настраивается таким же образом как и в классе Publisher, только меняем местами publisher_id и authorbook_id
package HibernateApps;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name = “author_books”)
public class AuthorBooks {
@Id
@GeneratedValue(
strategy=GenerationType.IDENTITY
)
@Column(name=”id”)
private int id;
@Column(name=”name”)
private String bookName;
@ManyToOne(cascade ={CascadeType.DETACH,
CascadeType.REFRESH,
CascadeType.PERSIST,
CascadeType.MERGE})
@JoinColumn(name=”author_id”)
private Author author;
//Также используем аннотацию
//@ManyToMany (Многие-ко-Многим).
//Многие AuthorBooks ко многим Publisher.
//Важно убрать CascadeType.REMOVE чтобы
//при удалении из БД какого-то из издательств
//не удалялись из БД книги напечатанные им.
@ManyToMany(cascade ={CascadeType.DETACH,
CascadeType.REFRESH,
CascadeType.PERSIST,
CascadeType.MERGE})
@JoinTable(name=”authorbooks_publisher”,
//Связь с таблицей publisher
//через промежуточную таблицу
//в этом классе настраиваем также
//как и в классе Publisher только
//как можно увидеть ниже
//в joinColumns теперь authorbook_id,
//а в inverseJoinColumns
//теперь publisher_id.
joinColumns=
@JoinColumn(name=”authorbook_id”),
inverseJoinColumns=
@JoinColumn(name=”publisher_id”))
private List publisher;
public AuthorBooks () {
}
public AuthorBooks(String bookName) {
this.bookName = bookName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
@Override
public String toString() {
return “Book [id=”
+ id + “, bookName=”
+ bookName + “]”;
}
}
Пример программы со связью Многие-ко-Многим:
package HibernateApps;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateApp {
public static void main(String[] args) {
//Добавим Publisher в sessionfactory
SessionFactory sessionFactory = new Configuration()
.configure(“hibernate.cfg.xml”)
.addAnnotatedClass(Author.class)
.addAnnotatedClass(AuthorInfo.class)
.addAnnotatedClass(AuthorBooks.class)
.addAnnotatedClass(Publisher.class)
.buildSessionFactory();
Session session = sessionFactory.getCurrentSession();
try {
session.beginTransaction();
//создаем издательства
Publisher publisher = new Publisher(“Yakaboo”);
Publisher publisher1 = new Publisher(“Vivat”);
Publisher publisher2 = new Publisher(“IPIO”);
//извлем три книги из БД
AuthorBooks authorbook =
session.get(AuthorBooks.class,1);
AuthorBooks authorbook1 =
session.get(AuthorBooks.class,2);
AuthorBooks authorbook2 =
session.get(AuthorBooks.class,3);
//Связываем первое издательство
//с первой и третьей книгой.
publisher.setOneBook(authorbook);
publisher.setOneBook(authorbook2);
//Связываем второе издательство
//с первой, второй и третьей книгой.
publisher1.setOneBook(authorbook);
publisher1.setOneBook(authorbook1);
publisher1.setOneBook(authorbook2);
//Связываем третье издательство
//со второй и третьей книгой.
publisher2.setOneBook(authorbook1);
publisher2.setOneBook(authorbook2);
//сохраняем издательства в базу
session.save(publisher);
session.save(publisher1);
session.save(publisher2);
session.getTransaction().commit();
} catch (Exception e) {
session.getTransaction().rollback();
e.printStackTrace();
} finally{
session.close();
}
}
}
Давайте запустим нашу программу.
Как видим, сначала произошло три select запроса на выборку книг (как мы помним, мы извлекали из БД три книги с помощью get).
Далее произошла вставка (insert) трех издательств в таблицу publisher и потом произошло связывание издательств и книжек посредством вставки идентификаторов в промежуточную таблицу.
Как видим, вставка издательств в таблицу publisherпроизошла успешно. Можно убедиться, что в промежуточной таблице книги и издательства связаны в соответствии с тем как мы их связывали в программе