Quan hệ Many To Many cột mở rộng Hibernate với Spring Boot

Link Source: Quan hệ Many To Many cột mở rộng Hibernate với Spring Boot
Thể loại: Java, Lập trình
Tags: Hibernate Framework, Học hành, Lập trình, Spring Framework

Hướng dẫn tạo quan hệ liên kết nhiều nhiều (many to many) tạo bản phụ trong hibernate spring boot


many-to-many-extracolumns (3)


Many To Many Join Extra Column Relationship Mapping with Spring Boot


Trong bài này mình sẽ hướng dẫn dùng annotation manytomany thêm bảng phụ (trung gian) trong hibernate + spring boot + mysql


Lưu ý bài này mở rộng từ bài hướng dẫn dùng annotation manytomany không thêm bảng phụ (trung gian) trong hibernate + spring boot + mysql. Nếu bạn chưa đọc thì hãy đọc trước bài đó, bài này mình sẽ không viết chi tiết như bài trước đó mà chỉ tập trung vào phần trọng tâm mở rộng thôi!


Hướng dẫn quan hệ nhiều nhiều (many to many) cột mở rộng hibernate jpa với Spring Boot Project


Tạo bảng trong cơ sở dữ liệu


Trong bài này chúng ta sẽ có 3 bảng trong cơ sở dữ liệu: book, publisher, book_publisher. Vì thế bên Java tương ứng sẽ có 3 entity là Book.javaPublisher.java và BookPublisher.java


many-to-many-extracolumns (3)


Lược đồ cơ sở dữ liệu như bạn thấy, trong bảng phụ ngoài 2 khóa chính cũng là 2 khóa ngoại như bài trước thì còn có 1 field là published_date


Mapping a many-to-many extra columns relationship with Spring Boot, Spring Data JPA and MySQL.


Database many-to-many extra columns code mysql:


CREATE DATABASE IF NOT EXISTS `jpa_manytomany_extracolumns` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `jpa_manytomany_extracolumns`;

--
-- Table structure for table `book`
--

DROP TABLE IF EXISTS `book`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `book` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `publisher`
--

DROP TABLE IF EXISTS `publisher`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `publisher` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;

--
-- Table structure for table `book_publisher`
--

DROP TABLE IF EXISTS `book_publisher`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `book_publisher` (
`book_id` int(10) unsigned NOT NULL,
`publisher_id` int(10) unsigned NOT NULL,
`published_date` datetime DEFAULT NULL,
PRIMARY KEY (`book_id`,`publisher_id`),
KEY `fk_bookpublisher_publisher_idx` (`publisher_id`),
CONSTRAINT `fk_bookpublisher_book` FOREIGN KEY (`book_id`) REFERENCES `book` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_bookpublisher_publisher` FOREIGN KEY (`publisher_id`) REFERENCES `publisher` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

Cấu trúc project spring boot


many-to-many-extracolumns (1)


Vào phần chính nào, mình dùng Eclipse + plugin Spring suite Tool để tạo project spring boot nhanh nhất.


Tạo project Spring Starter Project như hình


many-to-many-extracolumns (2)


Sau khi tạo xong bạn sẽ thấy có class Manytomany1Application.java và file pom.xml


Nội dung file Manytomany1Application.java


package com.qlam.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Manytomany2Application
public static void main(String[] args)
SpringApplication.run(Manytomany2Application.class, args);


Nội dung file pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.qlam</groupId>
<artifactId>manytomany2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>manytomany2</name>
<description>Demo project for Spring Boot shareeverythings.com</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>


</project>

Khai báo các thực thể JPA Entity tức là các class trong package model


File BookPublisher.java


package com.qlam.demo.model;

import javax.persistence.*;

import java.io.Serializable;
import java.util.Date;

@Entity
@Table(name = "book_publisher")
public class BookPublisher implements Serializable
private static final long serialVersionUID = 1L;

private Book book;
private Publisher publisher;
private Date publishedDate;

@Id
@ManyToOne
@JoinColumn(name = "book_id")
public Book getBook()
return book;


public void setBook(Book book)
this.book = book;


@Id
@ManyToOne
@JoinColumn(name = "publisher_id")
public Publisher getPublisher()
return publisher;


public void setPublisher(Publisher publisher)
this.publisher = publisher;


@Column(name = "published_date")
public Date getPublishedDate()
return publishedDate;


public void setPublishedDate(Date publishedDate)
this.publishedDate = publishedDate;


File Book.java


package com.qlam.demo.model;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Entity
public class Book
private int id;
private String name;
private Set<BookPublisher> bookPublishers;

public Book()


public Book(String name)
this.name = name;
bookPublishers = new HashSet<>();


@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public int getId()
return id;


public void setId(int id)
this.id = id;


public String getName()
return name;


public void setName(String name)
this.name = name;


@OneToMany(mappedBy = "book", cascade = CascadeType.ALL, orphanRemoval = true)
public Set<BookPublisher> getBookPublishers()
return bookPublishers;


public void setBookPublishers(Set<BookPublisher> bookPublishers)
this.bookPublishers = bookPublishers;


File Publisher.java


package com.qlam.demo.model;

import javax.persistence.*;
import java.util.Set;

@Entity
public class Publisher
private int id;
private String name;
private Set<BookPublisher> bookPublishers;

public Publisher()



public Publisher(String name)
this.name = name;


@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public int getId()
return id;


public void setId(int id)
this.id = id;


public String getName()
return name;


public void setName(String name)
this.name = name;


@OneToMany(mappedBy = "publisher")
public Set<BookPublisher> getBookPublishers()
return bookPublishers;


public void setBookPublishers(Set<BookPublisher> bookPublishers)
this.bookPublishers = bookPublishers;


Tạo Spring Data JPA Repository


File BookRepository.java


package com.qlam.demo.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.qlam.demo.model.Book;

public interface BookRepository extends JpaRepository<Book, Integer>

File PublisherRepository.java


package com.qlam.demo.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.qlam.demo.model.Publisher;

public interface PublisherRepository extends JpaRepository<Publisher, Integer>

Khai báo chuỗi kết nối trong file Application Properties


Trong file application.properties thêm các đoạn code kết nối với mysql


spring.datasource.url=jdbc:mysql://localhost/jpa_manytomany_extracolumns
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

Bạn cần lưu ý 3 dòng đầu tùy chỉnh lại cho đúng với kết nối mysql của bạn.


Chạy thử chương trình


Mình sẽ tạo 2 book A,B và 2 publisher A và B. Sau đó Book A sẽ có 2 publisher là A và B, còn book B chỉ có publisher là B thôi.


Trong file Manytomany2ApplicationTests.java trong phần src/test/resources mình tạo một số đối tượng để test thử như bên dưới.


package com.qlam.demo;

import java.util.Date;

import javax.transaction.Transactional;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import com.qlam.demo.model.Book;
import com.qlam.demo.model.BookPublisher;
import com.qlam.demo.model.Publisher;
import com.qlam.demo.repository.BookRepository;
import com.qlam.demo.repository.PublisherRepository;

@RunWith(SpringRunner.class)
@SpringBootTest
public class Manytomany2ApplicationTests
@Autowired
private BookRepository bookRepository;

@Autowired
private PublisherRepository publisherRepository;

@Transactional
@Test
public void contextLoads()
Book bookA = new Book("Book A");
Book bookB = new Book("Book B");

Publisher publisherA = new Publisher("Publisher A");
Publisher publisherB = new Publisher("Publisher B");

BookPublisher bookPublisher = new BookPublisher();
bookPublisher.setBook(bookA);
bookPublisher.setPublisher(publisherA);
bookPublisher.setPublishedDate(new Date());
bookA.getBookPublishers().add(bookPublisher);

BookPublisher bookPublisher2 = new BookPublisher();
bookPublisher2.setBook(bookA);
bookPublisher2.setPublisher(publisherB);
bookPublisher2.setPublishedDate(new Date());
bookA.getBookPublishers().add(bookPublisher2);

BookPublisher bookPublisher3 = new BookPublisher();
bookPublisher3.setBook(bookB);
bookPublisher3.setPublisher(publisherB);
bookPublisher3.setPublishedDate(new Date());
bookB.getBookPublishers().add(bookPublisher3);

publisherRepository.save(publisherA);
publisherRepository.save(publisherB);
bookRepository.save(bookA);
bookRepository.save(bookB);
// test
System.out.println(bookA.getBookPublishers().size());


Kết quả chạy, mình chỉ copy phần chính thôi!


Hibernate: insert into publisher (name) values (?)
Hibernate: insert into publisher (name) values (?)
Hibernate: insert into book (name) values (?)
Hibernate: insert into book_publisher (published_date, publisher_id, book_id) values (?, ?, ?)
Hibernate: insert into book_publisher (published_date, publisher_id, book_id) values (?, ?, ?)
Hibernate: insert into book (name) values (?)
2

Kết quả là trong bảng Book và Publisher sẽ có 2 Book và 2 Publisher tương ứng. Còn trong bảng book_publisher sẽ có 3 dòng trong đó có 1 book sẽ có 2 publisher và 1 book sẽ có 1 publisher.


Download source code


 



Link Source: Quan hệ Many To Many cột mở rộng Hibernate với Spring Boot
Comment