一對一共享主鍵
下面我們直接通過實例來講解共享主鍵配置:
主鍵主控方:Article
package com.chenhao.model;
@Table(name = "t_article2")
@Entity
public class Article {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String title;
@OneToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY,optional = false)
@PrimaryKeyJoinColumn//配置共享主鍵,否則會額外生成外鍵關聯列
private ArticleContent articleContent;
//忽略get 和set方法
}
引用主鍵方:ArticleContent。這是共享主鍵關聯的關鍵配置地方所在類
package com.chenhao.model;
@Table(name = "t_article_content")
@Entity
public class ArticleContent {
@Id
@GenericGenerator(name = "foreignKey" ,//生成器名稱
strategy = "foreign",//使用hibernate的外鍵策略
parameters = @Parameter(value = "article",name = "property"))//指定成員屬性中的article所在類的主鍵爲本類的主鍵,這裏的參數屬性name必須爲"property"
@GeneratedValue(generator = "foreignKey")//使用上述定義的id生成器
private Integer id;
@Lob
private String content;
//如果試圖不加此註解來形成單向關聯,會拋出異常,
//因爲設置了共享主鍵這裏是否配置mapperBy放棄維護關聯關係已失去作用。
@OneToOne(cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn//如果不加此註解,hibernate會在數據庫默認生成一條article_id屬性
private Article article;
//忽略get 和set方法
下面是我們的測試方法:
Article article = new Article();
article.setTitle("title");
ArticleContent articleContent = new ArticleContent();
articleContent.setContent("content");
article.setArticleContent(articleContent);
articleContent.setArticle(article);//必須雙方設置
session.save(article);
下面是幾點需要注意的:
1.在設置屬性ID的時候必須注意字段的長度,如筆者這樣使用Oracle的sequence來生成ID,其長度有14位之長,則應選擇hibernate類型long,對應的實體中應選擇Long,這樣不會出現溢出的情況。
2.在測試的時候必須要注意這兩張表之間因爲已經存在了一對一的關係,所以我們不能只寫articleContent.setArticle(article);而忽略了articleContent.setArticle(article);這樣在做插入的時候會報出attempted to assign id from null one-to-one property: address的錯誤.
3.如果不寫cascade=”all”或者寫成cascade=”none”的話,即使寫了article.setArticleContent(articleContent);和articleContent.setArticle(article);也不會發生任何事情,只有user會被存儲。
4.one-to-one的效率問題——-one-to-one在查詢時,總是查出和主表關聯的表,而且one-to-one的lazy屬性只有false proxy no-proxy三種,沒有true。outer-join=”false”也只是徒增查詢語句條數,把本來的一條sql語句變成多條。所以在one-to-one這種一對一的關係不是很強的情況下(one-to-one關係強即總是查出這所有的幾個關聯表),或者是在一張表中存在多個one-to-one的情況下,使用最好one-to-many來代替one-to-one。