前言
關系映射只有正確的配置才能生成正確而有效的SQL語句,通過上一節對一對一關系的講解,我們發現其實並不難,在關系數據庫系統中,一對多關聯基於外鍵列鏈接兩個表,以便子表記錄引用父表行的主鍵。
one to many關系映射
對於一對多關系映射也存在單向和雙向關聯,在JPA中,我們通過注解@OneToMany和@ManyToOne來進行單向或雙向關聯,雙向關聯要求目標實體映射提供@ManyToOne注解,該注解負責控制關,單向關聯通過注解@OneToMany配置更簡單,因為它是定義關系的父方,接下來我們分別來講解單向和雙向關聯。
單向關聯(@OneToMany)
我們給出實體Blog和Post實體,一個博客對應下有多篇發表文章,而一篇文章只屬於特定博客,如下:
@Entity public class Blog { @Id private Long id; @Column private String name; @OneToMany(cascade = CascadeType.ALL) private List<Post> posts = new ArrayList<>(); public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void addPost(Post post) { posts.add(post); post.setBlog(this); } public void addPosts(List<Post> posts) { for (Post p : posts) { addPost(p); } } }
@Entity public class Post { @Id @GeneratedValue private Long id; @ManyToOne private Blog blog; private String title; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Blog getBlog() { return blog; } public void setBlog(Blog blog) { this.blog = blog; } }

如上就是默認情況下通過注解@OneToMany配置生成單向關聯的情況,這看起來更像是多對多數據庫關聯,而不是一對多關系,理論上應該只有兩個表而不是三個表,所以我們需要使用不必要的空間來存儲數據,這樣效率不高,我們只有兩個外鍵,而不僅僅是一個外鍵,但是,由於我們最有可能對這些外鍵進行索引,因此我們將需要兩倍的內存來緩存此關聯的索引。
單向關聯(具有@JoinColumn的@OneToMany)
要解決生成上述額外的聯接表問題,我們只需要在目標實體集合中繼續添加@JoinColumn注解,通過@JoinColumn注解可幫助Hibernate找出在post表中有一個blog_id外鍵列來定義此關聯。如下:
@OneToMany(cascade = CascadeType.ALL) @JoinColumn(name = "blog_id") private List<Post> posts = new ArrayList<>();

接下來我們打開會話來保存數據看看,如下:
Blog blog = new Blog(); blog.setId(1L); blog.setName("Jeffcky"); Post post = new Post(); post.setTitle("hibernate4"); Post post1 = new Post(); post1.setTitle("hibernate5"); blog.addPosts(Arrays.asList(post, post1)); ...... session.save(blog);

此時我們發現對於實體Post中的外鍵blog_id並不是直接插入,而是在插入后再進行更新,這里涉及到JPA中的實體狀態,很明顯在處理目標集合之前就進行了持久化操作,如此這樣,由於目標實體不存儲此信息,因此Hibernate首先插入沒有外鍵的子記錄,然后在處理目標集合階段,對外鍵列進行更新。
雙向關聯(@OneToMany)
和我們一節講解一對一關系映射一樣,我們需要通過指定mappedBy屬性來配置雙向關聯,對目標實體集合和目標實體分別進行如下配置
@OneToMany(mappedBy = "blog", cascade = CascadeType.ALL) private List<Post> posts = new ArrayList<>();
@ManyToOne
private Blog blog;


總結
本節我們講解了一對多映射關系,其實和一對一關系映射差不多,本文到此結束,講完多對多關系,我們進入到對數據的操作。
