Composite Primary Keys trong JPA – Hibernate

Primary key(khoá chính) là thành phần không thể thiếu của một bảng trong database dùng để định danh một dòng dữ liệu trong database. Thông thường có 2 cách để chọn primary key là natural keys và technical keys.

Trong Natural keys các thuộc tính là những thông tin của dữ liệu thực ví dụ email và mssv được chọn là primary key của bảng SinhVien. Trong khi Technical keys thường chỉ chứa một thuộc tính và không liên quan đến thông tin thực ví dụ như một số nguyên tăng dần, UUID etc. 

Như vậy có thể thấy rằng đối với natural keys thì primary key có thể chứa nhiều hơn một thuộc tính hay còn gọi là Composite Primary key.

Composite Primary Keys

Composite Primary key còn được gọi tắt là composite key – chứa 2 hoặc nhiều hơn các thuộc tính trong primary key cho một table trong database.

Trong JPA chúng ta có 2 cách để định nghĩa một composite key với @IdClass@EmbeddedId annotation.

Trước khi định nghĩa một composite key chúng ta cùng chú ý một số quy định sau:

@IdClass annotation

Giả sử rằng chúng ta có bảng Account có 2 cột accountNumberaccountType được chọn làm composite key.

Chúng ta sẽ ánh xạ một composite class theo đặc tả của JPA như sau.

@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class AccountId implements Serializable {
    private String accountNumber;

    private String accountType;
}

Lưu ý để code ngắn gọn mình đã sử dụng Lombok để sinh code tự động tương ứng:

Đến với ánh xạ Account table, chúng ta cùng sử dụng @IdClass annotation với giá trị AccountId.class. Sau đó cùng khai báo lại các thuộc tính của AccountId class trong Account class và đánh dấu với @Id annotation.

@Entity
@IdClass(AccountId.class)
@Getter
@Setter
@AllArgsConstructor
public class Account {
    @Id
    private String accountNumber;

    @Id
    private String accountType;

    private String name;
}

Để insert data xuống Account table chúng ta có thể thử đoạn code sau. Lưu ý đây chỉ là đoạn code mẫu. Mã nguồn đầy đủ sẽ được thêm vào cuối bài viết.

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Account account = new Account("842582", "CREDIT", "ACB");
em.persist(account);

@EmbeddedId annotation

Có thể thấy một nhược điểm rất lớn khi sử dụng @IdClass là mặc dù đã định nghĩa một class chứa các thuộc tính của composite key nhưng chúng ta vẫn phải khai báo lại trong entity class.

Đối với @EmbeddedId annotation chúng ta chỉ cần định nghĩa composite key class chứa các thuộc tính của composite key và đánh dấu nó với @Embeddable annotation.

@Embeddable
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
public class BookId implements Serializable {
    private String title;
    private String language;
}

Tiếp theo để ánh xạ Book table với composite keyBookId class thì chỉ cần khai báo nó trong Book entity với @EmbeddedId.

@Entity
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Book {
    @EmbeddedId
    private BookId bookId;

    private String author;
}

Lần nữa, để insert dữ liêu xuống Book table thì chúng ta chỉ cần làm như sauLưu ý đây chỉ là đoạn code mẫu. Mã nguồn đầy đủ sẽ được thêm vào cuối bài viết.

BookId bookId = new BookId("BOOK_OO1", "VN");
Book book = new Book(bookId, "shareprogramming.net");
em.persist(book);

Sự khác nhau giữa @IdClass và @EmbeddedId

Như chúng ta vừa thấy thì điểm khác biệt lớn nhất có thể thấy là với @IdClass chúng ta cần định nghĩa các thuộc tính của composite key 2 lần trong AccountIdAccount còn với @EmbeddedId thì không cần.

Một điểm khác nhau khi truy vấn dữ liệu:

Đối với @IdClass khi muốn truy vấn sử dụng một trong số các thuộc tính của composite key.

SELECT account.accountNumber FROM Account account

Còn với @EmbeddedId chúng ta phải thông qua BookId class

SELECT book.bookId.title FROM Book book

Từ điểm trên, @IdClass sẽ hữu dụng khi mà các thuộc tính trong composite key không thay đổi, chúng ta có thể truy vấn dữ liệu thông qua một trong số các thuộc tính của composite key. Trong khi, nếu chúng ta thường truy vấn thông qua một object composite key thì @EmbeddedId có thể hữu dụng hơn.

Tóm lược

Thoạt nhìn có lẽ có thể thấy rằng sử dụng @IdClass annotation có vẽ phiền phức khi mà chúng ta phải định nghĩa các thuộc tính của composite key đến 2 lần. Tuy nhiên từ các điểm phân tích trên mong rằng các bạn có thể hiểu mục đích sử dụng riêng của chúng, không phải tự nhiên mà nó được Hibernate cung cấp đến người dùng.

Sau cùng, các bạn có thể tham khảo mã nguồn được mình công khai trên github.

Nếu vẫn chưa biết cách cấu hình một project JPA – Hibermate thì bạn có thể tham khảo bài viết sau để thực hành.

Nguồn tham khảo

https://www.baeldung.com/jpa-composite-primary-keys

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x