Nội dung bài viết
Trong cơ sở dữ liệu, quan hệ n-n (many-to-many) là một loại quan hệ rất phổ biến. Ví dụ, một địa chỉ có thể chứa nhiều người (gia đình), và một người có thể có nhiều địa chỉ. Để biểu thị quan hệ này trong cơ sở dữ liệu và thao tác với nó trong ứng dụng Java, chúng ta sử dụng Hibernate, một framework ORM (Object-Relational Mapping) phổ biến.
Trong bài viết này, chúng ta sẽ tìm hiểu cách sử dụng Hibernate để biểu thị và quản lý quan hệ @ManyToMany giữa hai đối tượng, ví dụ là "Person" và "Address", bằng cách sử dụng ngôn ngữ lập trình Java.
Chuẩn bị Dự Án
Trước khi bắt đầu, chúng ta cần tạo một dự án Java Spring Boot với sự hỗ trợ của Hibernate. Bạn có thể sử dụng Gradle hoặc Maven để quản lý dự án. Dưới đây là một ví dụ về cấu hình Gradle:
plugins {
id 'org.springframework.boot' version '2.5.4'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.projectlombok:lombok:1.18.22'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
Trong ví dụ này, chúng ta sử dụng Spring Boot Starter cho Spring Data JPA, Spring Web, và thư viện Lombok để giảm bớt mã nguồn. Chúng ta cũng sử dụng H2 Database để làm cơ sở dữ liệu.
Tạo Entity
Để biểu thị quan hệ @ManyToMany, chúng ta cần tạo hai đối tượng (entity) tương ứng: "Person" và "Address".
Entity "Person"
import lombok.*;
import javax.persistence.*;
import java.util.Collection;
@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany(mappedBy = "persons")
private Collection<Address> addresses;
}
@Entity
: Đánh dấu lớp này là một entity.@Id
: Đánh dấu trườngid
là khóa chính.@GeneratedValue
: Xác định cách tạo giá trị cho trườngid
.@ManyToMany
: Xác định quan hệ many-to-many với entity "Address".mappedBy
: Chỉ định trường trong "Address" quản lý quan hệ này.
Entity "Address"
import lombok.*;
import javax.persistence.*;
import java.util.Collection;
@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String city;
private String province;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(
name = "address_person",
joinColumns = @JoinColumn(name = "address_id"),
inverseJoinColumns = @JoinColumn(name = "person_id")
)
private Collection<Person> persons;
}
@Entity
: Đánh dấu lớp này là một entity.@Id
: Đánh dấu trườngid
là khóa chính.@GeneratedValue
: Xác định cách tạo giá trị cho trườngid
.@ManyToMany
: Xác định quan hệ many-to-many với entity "Person".cascade = CascadeType.ALL
: Đảm bảo các thay đổi trong "Address" cũng được áp dụng vào "Person".@JoinTable
: Xác định tên bảng trung gian và các khóa ngoại.
Tạo Repository
Chúng ta cần tạo các repository để thực hiện các thao tác truy vấn dữ liệu.
import org.springframework.data.jpa.repository.JpaRepository;
public interface PersonRepository extends JpaRepository<Person, Long> {
}
import org.springframework.data.jpa.repository.JpaRepository;
public interface AddressRepository extends JpaRepository<Address, Long> {
}
Thực Hiện Ví dụ
Thêm Dữ Liệu
Chúng ta sẽ thêm dữ liệu vào cơ sở dữ liệu bằng cách sử dụng CommandLineRunner
.
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import lombok.RequiredArgsConstructor;
@SpringBootApplication
@RequiredArgsConstructor
public class ManyToManyExampleApplication implements CommandLineRunner {
private final PersonRepository personRepository;
private final AddressRepository addressRepository;
public static void main(String[] args) {
SpringApplication.run(ManyToManyExampleApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
Address hanoi = Address.builder()
.city("Hanoi")
.province("HN")
.build();
Address hatay = Address.builder()
.city("Hai Phong")
.province("HP")
.build();
Person person1 = Person.builder()
.name("John")
.build();
Person person2 = Person.builder()
.name("Jane")
.build();
hanoi.setPersons(List.of(person1, person2));
hatay.setPersons(List.of(person1));
addressRepository.save(hanoi);
addressRepository.save(hatay);
System.out.println("Data saved successfully.");
}
}
Query Dữ Liệu
Chúng ta có thể truy vấn dữ liệu theo cách thông qua repository.
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import lombok.RequiredArgsConstructor;
@SpringBootApplication
@RequiredArgsConstructor
public class ManyToManyExampleApplication implements CommandLineRunner {
private final PersonRepository personRepository;
private final AddressRepository addressRepository;
public static void main(String[] args) {
SpringApplication.run(ManyToManyExampleApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
// Query dữ liệu
Address hanoi = addressRepository.findById(1L).orElse(null);
if (hanoi != null) {
System.out.println("City: " + hanoi.getCity());
System.out.println("Persons in Hanoi: " + hanoi.getPersons());
}
}
}
Khi bạn chạy ứng dụng, dữ liệu sẽ được thêm vào cơ sở dữ liệu và kết quả truy vấn dữ liệu từ bảng "Address" sẽ được hiển thị.
City: Hanoi Persons in Hanoi: Person(id=1, name=John), Person(id=2, name=Jane)