STACKJAVA

Code ví dụ Hibernate @ManyToMany – Quan hệ nhiều nhiều

Code ví dụ Hibernate @ManyToMany – Quan hệ nhiều nhiều.

(Xem thêm: Hướng dẫn tự học Hibernate)

Trong thiết kế database,  khi xuất hiện quan hệ nhiều nhiều (n-n) thì ta sẽ tạo một bảng trung gian để chuyển quan hệ nhiều nhiều đó thành 2 quan hệ một nhiều.

Ví dụ:

Ví dụ mình có 1 bảng product (sản phẩm) và 1 bảng category (danh mục). Quan hệ giữa hai bảng này là nhiều – nhiều vì 1 sản phẩm có thể thuộc nhiều danh mục khác nhau, một danh mục cũng có thể chứa nhiều sản phẩn khác nhau.

Khi thiết kế database ta sẽ tạo 1 bảng chung gian để biến đổi nó thành 2 quan hệ một nhiều:

Ở đây mình tạo bảng trung gian là product_category, từ quan hệ nhiều nhiều giữa product với category nó sẽ thành 2 quan hệ một nhiều là product với product_categorycategory với product_category

Tạo database

CREATE SCHEMA `hibernate-demo-4` ;

CREATE TABLE `hibernate-demo-4`.`product` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(45) NULL,
  PRIMARY KEY (`id`));

  
CREATE TABLE `hibernate-demo-4`.`category` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(45) NULL,
  PRIMARY KEY (`id`));

 
 CREATE TABLE `hibernate-demo-4`.`product_category` (
  `product_id` INT NOT NULL,
  `category_id` INT NOT NULL,
  PRIMARY KEY (`product_id`, `category_id`),
  CONSTRAINT `fk-category`
    FOREIGN KEY (`category_id`)
    REFERENCES `hibernate-demo-4`.`category` (`id`),
  CONSTRAINT `fk-product`
    FOREIGN KEY (`product_id`)
    REFERENCES `hibernate-demo-4`.`product` (`id`));

Các công nghệ sử dụng:

Cấu trúc project

Các thư viện sử dụng

<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>stackjava.com</groupId>
  <artifactId>HibernateManyToManyDemo</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <properties>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
    <hibernate.version>5.3.6.Final</hibernate.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>${hibernate.version}</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-entitymanager</artifactId>
      <version>${hibernate.version}</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.46</version>
    </dependency>
  </dependencies>


</project>

File cấu hình hibernate, kết nối tới MySQL

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd" version="2.1">
  <persistence-unit name="persistence">
    <description>Demo Hibernate Entity Manager</description>
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <properties>
      <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
      <property name="javax.persistence.jdbc.url"
        value="jdbc:mysql://localhost:3306/hibernate-demo-4" />
      <property name="javax.persistence.jdbc.user" value="root" />
      <property name="javax.persistence.jdbc.password" value="admin1234" />
      <property name="hibernate.show_sql" value="true" />
    </properties>
  </persistence-unit>
</persistence>

Trong ví dụ này mình sử dụng entityManager nên sẽ khai báo file persistence.xml nếu các bạn sử dụng hibernateSession thì có thể khai báo file hibernate.cfg.xml

(Xem lại: Code ví dụ Hibernate EntityManager, EntityManagerFactory)

(Xem lại: Code ví dụ Hibernate Session, SessionFactory)

Các class entities

package stackjava.com.hibernatedemo.entities;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.*;

@Entity
@Table(name = "category")
public class Category {

  @Id
  @Column(name = "id")
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  @Column(name = "name")
  private String name;

  @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
  @JoinTable(name = "product_category", 
    joinColumns = { @JoinColumn(name = "category_id") }, 
    inverseJoinColumns = {@JoinColumn(name = "product_id") })
  private Set<Product> products = new HashSet<>();

  @Override
  public String toString() {
    return "Category [id=" + id + ", name=" + name + "  - products size: " + products.size() + "]";
  }
  
  // setter - getter

}
package stackjava.com.hibernatedemo.entities;

import java.util.Set;

import javax.persistence.*;

@Entity
@Table(name = "product")
public class Product {

  @Id
  @Column(name = "id")
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  @Column(name = "name")
  private String name;

  @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
  @JoinTable(name = "product_category", 
    joinColumns = { @JoinColumn(name = "product_id") }, 
    inverseJoinColumns = {@JoinColumn(name = "category_id") })
  private Set<Category> categories = new HashSet<>();

  @Override
  public String toString() {
    return "Product [id=" + id + ", name=" + name + "  - categories size: " + categories.size() +"]";
  }

  // getter - setter
  
}

Demo 1

Insert 1 category với nhiều product

package stackjava.com.hibernatedemo;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import stackjava.com.hibernatedemo.entities.Category;
import stackjava.com.hibernatedemo.entities.Product;

public class DemoInsert1 {

  public static void main(String[] args) {
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("persistence");
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    entityManager.getTransaction().begin();

    Category category = new Category("Electronic Device");
    Product product1 = new Product("Television");
    Product product2 = new Product("Iphone");
    Product product3 = new Product("Samsung Galaxy S9");
    
    Set<Product> products = new HashSet<>();
    products.add(product1);
    products.add(product2);
    products.add(product3);
    
    entityManager.persist(category);
    entityManager.getTransaction().commit();
    
    System.out.println("-------------------------------");
    System.out.println(category);
    System.out.println(product1);
    System.out.println(product2);
    System.out.println(product3);
    entityManager.close();
    entityManagerFactory.close();
  }

}

Kết quả:

Hibernate: insert into category (name) values (?)
Hibernate: insert into product (name) values (?)
Hibernate: insert into product (name) values (?)
Hibernate: insert into product (name) values (?)
-------------------------------
Category [id=1, name=Electronic Device  - products size: 3]
Product [id=2, name=Television  - categories size: 0]
Product [id=3, name=Iphone  - categories size: 0]
Product [id=1, name=Samsung Galaxy S9  - categories size: 0]

Ở đây mình đang để cascade = CascadeType.ALL nên khi persist category, các product của category cũng được persist theo

(Xem lại: Code ví dụ Hibernate cascade, annotation @Cascade.)

Demo 2

Persist 1 product với nhiều category.

Bây giờ mình thực hiện lấy product có id = 2 vừa tạo ở trên, thêm mới category cho nó và thực hiện lưu lại.

package stackjava.com.hibernatedemo;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import stackjava.com.hibernatedemo.entities.Category;
import stackjava.com.hibernatedemo.entities.Product;

public class DemoInsert2 {

  public static void main(String[] args) {
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("persistence");
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    entityManager.getTransaction().begin();

    Category category = new Category("Home Applicances");
    
    Product product = entityManager.find(Product.class, 2);
    
    product.getCategories().add(category);
    
    entityManager.getTransaction().commit();
    System.out.println("--------- after insert -------------");
    System.out.println(category);
    System.out.println(product);
    entityManager.close();
    entityManagerFactory.close();
  }

}

Kết quả:

Hibernate: select product0_.id as id1_1_0_, product0_.name as name2_1_0_ from product product0_ where product0_.id=?
Hibernate: select categories0_.product_id as product_1_2_0_, categories0_.category_id as category2_2_0_, category1_.id as id1_0_1_, category1_.name as name2_0_1_ from product_category categories0_ inner join category category1_ on categories0_.category_id=category1_.id where categories0_.product_id=?
Hibernate: insert into category (name) values (?)
Hibernate: insert into product_category (product_id, category_id) values (?, ?)
--------- after insert -------------
Category [id=2, name=Home Applicances  - products size: 0]
Product [id=2, name=Television  - categories size: 2]

Check lại database:

Bảng category

Bảng product

Bảng product_category

Demo 3

Thực hiện lấy dữ liệu của category có id = 1, và product có id = 2 và in ra dữ liệu của chúng:

package stackjava.com.hibernatedemo;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import stackjava.com.hibernatedemo.entities.Category;
import stackjava.com.hibernatedemo.entities.Product;

public class DemoSelect {

  public static void main(String[] args) {
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("persistence");
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    entityManager.getTransaction().begin();

    Category category = entityManager.find(Category.class, 1);
    System.out.println(category);
    category.getProducts().forEach(p -> System.out.println(p));
    
    System.out.println("-------------------------------");
    Product product = entityManager.find(Product.class, 2);
		System.out.println(product);
    product.getCategories().forEach(c -> System.out.println(c));
    entityManager.close();
    entityManagerFactory.close();
  }

}

Kết quả:

Category [id=1, name=Electronic Device  - products size: 3]
Product [id=3, name=Iphone  - categories size: 1]
Product [id=1, name=Samsung Galaxy S9  - categories size: 1]
Product [id=2, name=Television  - categories size: 2]
-------------------------------
Product [id=2, name=Television  - categories size: 2]
Category [id=1, name=Electronic Device  - products size: 3]
Category [id=2, name=Home Applicances  - products size: 1]

 

Okay, Done!

Download code ví dụ trên tại đây.

 

References:

https://docs.jboss.org/…/ManyToMany.html