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:

Code ví dụ Hibernate @ManyToMany - Quan hệ nhiều 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

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

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)

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

}
  • Để biểu thị mối quan hệ nhiều nhiều ta dùng annotation @ManyToMany
  • Annotation @JoinTable sẽ chỉ rõ bảng trung gian trong thuộc tính name, thuộc tính joinColumns sẽ chỉ rõ column mapping với tale hiện tại, thuộc tính inverseJoinColumns sẽ chỉ rõ column mapping với table còn lại
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

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

Bảng product

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

Bảng product_category

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

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

stackjava.com