Annotation @ManyToOne trong JPA được dùng để thể hiện mối quan hệ nhiều – một giữa hai bảng trong một database nào đó. Ở đó, nhiều record trong bảng A có mối quan hệ với một record trong bảng B. Ví dụ như: nhiều sinh viên khác nhau có thể có cùng lớp học. Trong bài viết này, chúng ta sẽ cùng nhau tìm hiểu sâu về annotation này nhé các bạn!
Để dễ hình dung, mình sẽ lấy mối quan hệ giữa sinh viên và lớp học để làm ví dụ. Cấu trúc database của hai bảng này như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
CREATE TABLE `clazz` ( `id` int(11) NOT NULL, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `student` ( `id` int(11) NOT NULL, `name` varchar(255) DEFAULT NULL, `clazz_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`), FOREIGN KEY (`clazz_id`) REFERENCES `clazz` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
OK …
- Đầu tiên, mình sẽ tạo một project để làm việc với ví dụ này như sau:
với dependency như sau:
1 2 3 4 5 |
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.2.11.Final</version> </dependency> |
Vì trong ví dụ này, mình làm việc với MySQL nên mình cũng sẽ thêm dependency cho MySQL Driver:
1 2 3 4 5 |
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>6.0.6</version> </dependency> |
- Tiếp theo, mình sẽ tạo 2 entity thể hiện 2 bảng clazz và student.
Nội dung của entity Clazz lúc này như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
package com.huongdanjava.jpamanytoone; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table public class Clazz { @Id @GeneratedValue private Integer id; @Column private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } |
và entity Student:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
package com.huongdanjava.jpamanytoone; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table public class Student { @Id @GeneratedValue private Integer id; @Column private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } |
- Bây giờ, chúng ta sẽ sử dụng annotation @ManyToOne để thể hiện mối quan hệ nhiều – một giữa hai entity Student và Clazz nhé các bạn.
Bởi vì, đây là mối quan hệ nhiều – một nhìn từ đối tượng sinh viên, do đó chúng ta sẽ đặt annotation @ManyToOne trong entity Student.
Mình sẽ thêm một field mới trong entity Student sử dụng với annotation @ManyToOne như sau:
1 2 3 4 5 6 7 8 9 10 |
@ManyToOne private Clazz clazz; public Clazz getClazz() { return clazz; } public void setClazz(Clazz clazz) { this.clazz = clazz; } |
Ở đây, mình chỉ dùng duy nhất một annotation @ManyToOne, ngoài ra không dùng bất kỳ cấu hình nào khác. Do đó, các cấu hình mặc định cho annotation này sẽ được sử dụng. Mình sẽ nói cho các bạn biết các giá trị đó là gì?
Như các bạn đã biết, trong một database bất kỳ, khái niệm mối quan hệ có nghĩa là một bảng trong database này có mối liên hệ với một bảng khác cũng trong database này luôn. Và khi một cột trong bảng này tham chiếu tới một khóa chính (thường là primary key) của bảng kia thì chúng ta gọi cột này là cột foreign key.
Trong JPA, nếu các bạn chỉ sử dụng duy nhất annotation @ManyToOne, thì tên của cột foreign key này sẽ được định nghĩa bằng một tên mặc định. Tên mặc định này sẽ được xây dựng dựa vào 2 entity. Nó là tên của biến mà chúng ta định nghĩa mối quan hệ giữa 2 entity với annotation @ManyToOne, trong ví dụ của chúng ta là biến clazz trong entity Student, theo sau là dấu gạch dưới và cuối cùng là tên của biến đóng vai trò là primary key trong entity kia, trong ví dụ này thì đó là biến id trong entity Clazz.
Do vậy, ở ví dụ này của chúng ta thì cột foreign key này sẽ có tên là clazz_id nằm trong bảng student.
Trong trường hợp, cột foreign key trong bảng student không trùng với tên mặc định được định nghĩa bởi JPA thì các bạn cần phải sử dụng thêm một annotation khác có tên là @JoinColumn để định nghĩa cột foreign key. Trong annotation này, chúng ta có một attribute là name để định nghĩa tên của cột foreign key. Trong ví dụ của chúng ta, chúng ta có thể thêm annotation @JoinColumn như sau:
1 2 3 |
@ManyToOne @JoinColumn(name = "clazz_id") private Clazz clazz; |
Hiện tại, trong bảng student chúng ta đã định nghĩa cột foreign key là clazz_id trùng với tên mặc định nên bây giờ chúng ta có thể sử dụng 2 entity ở trên rồi.
- Để làm việc với JPA, chúng ta cần phải thêm một tập tin cấu hình cho JPA, persistence.xml, nằm trong thư mục /src/main/resources/META-INF của project.
với nội dung như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<persistence version="2.1" 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_2_1.xsd"> <persistence-unit name="jpaexample" transaction-type="RESOURCE_LOCAL"> <class>com.huongdanjava.jpamanytoone.Clazz</class> <class>com.huongdanjava.jpamanytoone.Student</class> <exclude-unlisted-classes>true</exclude-unlisted-classes> <properties> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" /> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpaexample" /> <property name="javax.persistence.jdbc.user" value="root" /> <property name="javax.persistence.jdbc.password" value="123456" /> <property name="javax.persistence.schema-generation.database.action" value="drop-and-create" /> <property name="hibernate.format_sql" value="true" /> <property name="hibernate.use_sql_comments" value="true" /> </properties> </persistence-unit> </persistence> |
- Giờ, mình sẽ viết code để thêm một lớp học với hai sinh viên như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
package com.huongdanjava.jpaexample; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; public class Example { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaexample"); EntityManager em = emf.createEntityManager(); EntityTransaction transaction = em.getTransaction(); transaction.begin(); Clazz clazz = new Clazz(); clazz.setName("Class A"); em.persist(clazz); Student student1 = new Student(); student1.setName("Khanh"); student1.setClazz(clazz); em.persist(student1); Student student2 = new Student(); student2.setName("Phung"); student2.setClazz(clazz); em.persist(student2); transaction.commit(); em.close(); emf.close(); } } |
Kết quả:
Như các bạn thấy, khi insert dữ liệu vào database, id của class A đã được tự động set vào giá trị của cột clazz_id trong bảng student.
DLQ_PTIT
Anh cho em hỏi, Em có 2 bảng kết nối với nhau: sale_order onetomany sale_orderline ,
Em có thể lôi được hết dữ liệu của bảng sale_order khi dùng sale_orderline để gọi, Nhưng em không thể dùng sale_order để lỗi dữ liệu của bảng sale_orderline ra được, anh có cách nào có thể giúp em không ạ. Em cảm ơn
tuyen
Anh ơi. khi mình đã có cột id của bảng khác nhưng mình ko muốn lấy cột id của bảng đó mà muốn lấy cột name của bảng đó chẳng hạn thì cần làm ntn vậy a
xyz
mình rút ra được một kết luận thông qua các bài viết của anh khanh là khi ta đứng ở một thì lấy được danh sách của nhiều tương ứng, còn đứng ở nhiều thì lấy được đối tượng của một.
xyz
anh ơi cac mối quan hệ của jpa như 5 bài anh viết thì trong hibernate cũng tương tự phải ko anh
Khanh Nguyen
Đúng rồi đó em!