Bi-directional Relationship trong Hibernate

·

4 min read

1. Giới thiệu về Bi-directional Relationship

Bi-directional Relationship là gì? Bi-directional Relationship là một mối quan hệ trong Hibernate mà cả hai phía của mối quan hệ đều biết về sự tồn tại của nhau. Điều này có nghĩa là nếu có hai entity A và B có mối quan hệ bi-directional, thì entity A có thể tham chiếu đến entity B và ngược lại.

Tại sao cần Bi-directional Relationship? Bi-directional Relationship giúp đảm bảo tính toàn vẹn của dữ liệu và dễ dàng hơn trong việc truy xuất và quản lý dữ liệu liên quan. Nó cũng giúp giảm thiểu lỗi và tăng tính rõ ràng của mã nguồn.

2. Ví dụ về Bi-directional One-to-Many và Many-to-One

Ví dụ cụ thể về One-to-Many và Many-to-One Giả sử chúng ta có hai entity UserAddress với mối quan hệ One-to-Many. Một User có thể có nhiều Address và một Address thuộc về một User.

Entity User

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

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

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

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Address> addresses = new HashSet<>();

    // Getters and setters

    public void addAddress(Address address) {
        addresses.add(address);
        address.setUser(this);
    }

    public void removeAddress(Address address) {
        addresses.remove(address);
        address.setUser(null);
    }
}

Entity Address

@Entity
@Table(name = "addresses")
public class Address {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

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

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

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    // Getters and setters
}

Chú thích:

  • Trong User, thuộc tính addresses sử dụng annotation @OneToMany với thuộc tính mappedBy chỉ định rằng mối quan hệ này được ánh xạ bởi thuộc tính user trong Address.

  • Trong Address, thuộc tính user sử dụng annotation @ManyToOne với @JoinColumn để xác định cột khóa ngoại user_id.

Thao tác thêm và xóa địa chỉ từ người dùng

User user = new User();
user.setUsername("johndoe");
user.setPassword("password123");

Address address1 = new Address();
address1.setStreet("123 Main St");
address1.setCity("Hometown");

Address address2 = new Address();
address2.setStreet("456 Elm St");
address2.setCity("Big City");

user.addAddress(address1);
user.addAddress(address2);

Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();

session.save(user);

transaction.commit();
session.close();

Trong ví dụ này, chúng ta tạo một đối tượng User và hai đối tượng Address, sau đó thêm các địa chỉ vào người dùng. Khi lưu người dùng, Hibernate sẽ tự động lưu các địa chỉ liên quan.

3. Ví dụ về Bi-directional Many-to-Many

Ví dụ cụ thể về Many-to-Many Giả sử chúng ta có hai entity StudentCourse với mối quan hệ Many-to-Many. Một Student có thể tham gia nhiều Course và một Course có thể có nhiều Student.

Entity Student

@Entity
@Table(name = "students")
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

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

    @ManyToMany
    @JoinTable(
        name = "student_courses",
        joinColumns = @JoinColumn(name = "student_id"),
        inverseJoinColumns = @JoinColumn(name = "course_id")
    )
    private Set<Course> courses = new HashSet<>();

    // Getters and setters

    public void addCourse(Course course) {
        courses.add(course);
        course.getStudents().add(this);
    }

    public void removeCourse(Course course) {
        courses.remove(course);
        course.getStudents().remove(this);
    }
}

Entity Course

@Entity
@Table(name = "courses")
public class Course {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

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

    @ManyToMany(mappedBy = "courses")
    private Set<Student> students = new HashSet<>();

    // Getters and setters
}

Chú thích:

  • Trong Student, thuộc tính courses sử dụng annotation @ManyToMany với @JoinTable để xác định bảng trung gian student_courses và các cột khóa ngoại student_idcourse_id.

  • Trong Course, thuộc tính students sử dụng annotation @ManyToMany với thuộc tính mappedBy chỉ định rằng mối quan hệ này được ánh xạ bởi thuộc tính courses trong Student.

Thao tác thêm và xóa khóa học từ sinh viên

Student student = new Student();
student.setName("John Doe");

Course course1 = new Course();
course1.setTitle("Mathematics");

Course course2 = new Course();
course2.setTitle("Physics");

student.addCourse(course1);
student.addCourse(course2);

Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();

session.save(student);

transaction.commit();
session.close();

Trong ví dụ này, chúng ta tạo một đối tượng Student và hai đối tượng Course, sau đó thêm các khóa học vào sinh viên. Khi lưu sinh viên, Hibernate sẽ tự động lưu các khóa học liên quan và cập nhật bảng trung gian student_courses.

4. Tóm tắt và lưu ý khi sử dụng Bi-directional Relationship

  • Đảm bảo tính toàn vẹn: Sử dụng các phương thức tiện ích như addAddress, removeAddress, addCourse, và removeCourse để đảm bảo rằng cả hai phía của mối quan hệ đều được cập nhật chính xác.

  • Lazy vs Eager Fetching: Chọn chiến lược fetching phù hợp để tối ưu hóa hiệu suất và tránh các vấn đề về hiệu suất hoặc LazyInitializationException.

  • Mapped By: Luôn sử dụng thuộc tính mappedBy để chỉ định phía chủ động của mối quan hệ, giúp Hibernate hiểu rõ hơn về cấu trúc và quản lý mối quan hệ hiệu quả.

Bi-directional Relationship là một kỹ thuật quan trọng trong Hibernate, giúp quản lý và truy xuất dữ liệu liên quan một cách hiệu quả và rõ ràng. Việc hiểu và áp dụng đúng kỹ thuật này sẽ giúp bạn xây dựng các ứng dụng Java sử dụng Hibernate mạnh mẽ và tối ưu hơn.