原文源自:https://stackabuse.com/a-guide-to-jpa-with-hibernate-relationship-mapping/
Java Persistence API(JPA)是Java生態系統的持久性標準。
它允許我們將我們的領域模型直接映射到數據庫結構中,
然后讓我們在代碼中靈活地操作對象--而不是去搞那些繁瑣的JDBC組件,如Connection、ResultSet等。
Our Example
在開始之前,讓我們提醒一下我們在本系列的前一部分中使用的例子。
我們的想法是繪制一所學校的模型,讓學生學習教師提供的課程。

首先,我們來定義一個關系。如果我們看一下我們的類圖,我們可以看到一些關系:
教師和課程--學生和課程--課程和教材。
學生和地址之間也有聯系,但它們并不被認為是關系。
這是因為地址不是一個實體(也就是說,它沒有被映射到一個自己的表中)。所以,就JPA而言,它不是一個關系。
- One-to-Many
- Many-to-One
- One-to-One
- Many-to-Many
Let's tackle these relationships one by one.
One-to-Many/Many-to-One
We'll get started with the One-to-Many and Many-to-One relationships, which are closely related. You could go ahead and say that they're the opposite sides of the same coin.
What's a One-to-Many relationship?
As its name implies, it's a relationship that links one entity to many other entities.
In our example, this would be a Teacher and their Courses. A teacher can give multiple courses, but a course is given by only one teacher (that's the Many-to-One perspective - many courses to one teacher).
Another example could be on social media - a photo can have many comments, but each of those comments belongs to that one photo.
Before diving into the details of how to map this relationship, let's create our entities:
@Entity public class Teacher { private String firstName; private String lastName; } @Entity public class Course { private String title; }
Now, the fields of the Teacher class should include a list of courses. Since we'd like to map this relationship in a database, which can't include a list of entities within another entity - we'll annotate it with a @OneToMany annotation:
@OneToMany private List<Course> courses;
How does JPA reflect this relationship in the database? Generally, for this type of relationship, we must use a foreign key in a table.
JPA does this for us, given our input on how it should handle the relationship. This is done via the @JoinColumn annotation:
@OneToMany @JoinColumn(name = "TEACHER_ID", referencedColumnName = "ID") private List<Course> courses;
Owning Side and Bidirectionality //只用放一邊
In the previous example, the Teacher class is called the owning side of the One-To-Many relationship. This is because it defines the join column between the two tables.
The Course is called the referencing side in that relationship.
Eager vs Lazy Loading
Another thing worth noting is eager and lazy loading. With all our relationships mapped, it's wise to avoid impacting the software's memory by putting too many entities in it if unnecessary.
Imagine that Course is a heavy object, and we load all Teacher objects from the database for some operation. We don't need to retrieve or use the courses for this operation, but they're still being loaded alongside the Teacher objects.
This can be devastating for the application's performance. Technically, this can be solved by using the Data Transfer Object Design Pattern and retrieving Teacher information without the courses.
However, this can be a massive overkill if all we're gaining from the pattern is excluding the courses.
Thankfully, JPA thought ahead and made One-to-Many relationships load lazily by default.
這意味著關系不會被立即加載,而是在實際需要時才加載。
In our example, that would mean until we call on the Teacher#courses method, the courses are not being fetched from the database.
By contrast, Many-to-One relationships are eager by default, meaning the relationship is loaded at the same time the entity is.
One-to-One
Now that we've set up the foundations of relationship mapping in JPA through One-to-Many/Many-to-One relationships and their settings, we can move on to One-to-One relationships.
This time, instead of having a relationship between one entity on one side and a bunch of entities on the other, we'll have a maximum of one entity on each side.
This is, for example, the relationship between a Course and its CourseMaterial. Let's first map CourseMaterial, which we haven't done yet:
@Entity public class CourseMaterial { @Id private Long id; private String url; }
The annotation for mapping a single entity to a single other entity is, unshockingly, @OneToOne.
Before setting it up in our model, let's remember that a relationship has an owning side - preferably the side which will hold the foreign key in the database.
In our example, that would be CourseMaterial as it makes sense that it references a Course (though we could go the other way around):
@OneToOne(optional = false) @JoinColumn(name = "COURSE_ID", referencedColumnName = "ID") private Course course;
There is no point in having material without a course to encompass it. That's why the relationship is not optional in that direction.
Speaking of direction, let's make the relationship bidirectional, so we can access the material of a course if it has one. In the Course class, let's add:
@OneToOne(mappedBy = "course") private CourseMaterial material;
Here, we're telling Hibernate that the material within a Course is already mapped by the course field of the CourseMaterial entity.
Also, there's no optional attribute here as it's true by default, and we could imagine a course without material (from a very lazy teacher).
In addition to making the relationship bidirectional, we could also add cascading operations or make entities load eagerly or lazily.
Many-to-Many
現在,最后但并非最不重要的: 多對多關系。我們將這些關系保留到最后,因為它們比前面的關系需要更多的工作。
實際上,在數據庫中,多對多關系涉及到一個中間表引用其他兩個表。
幸運的是,JPA完成了大部分的工作,我們只需要拋出一些注解,它就會為我們處理剩下的工作。
因此,在我們的例子中,Many-to-Many關系將是Student和Course實例之間的關系,因為一個學生可以參加多個課程,一個課程可以被多個學生關注。
為了映射Many-to-Many關系,我們將使用@ManyToMany注解。然而,這次我們還將使用 @JoinTable 注解來設置表示該關系的表:
@ManyToMany @JoinTable( name = "STUDENTS_COURSES", joinColumns = @JoinColumn(name = "COURSE_ID", referencedColumnName = "ID"), inverseJoinColumns = @JoinColumn(name = "STUDENT_ID", referencedColumnName = "ID") ) private List<Student> students;
Now, go over what's going on here. The annotation takes a few parameters. First of all, we must give the table a name. We've chosen it to be STUDENTS_COURSES.
After that, we'll need to tell Hibernate which columns to join in order to populate STUDENTS_COURSES. The first parameter, joinColumns defines how to configure the join column (foreign key) of the owning side of the relationship in the table. In this case, the owning side is a Course.
浙公網安備 33010602011771號