Hibernate一對一雙向關聯(外部索引鍵關聯)用法小結,hibernate一對一
這幾天在改一個項目源碼,遇到一個問題坑了很久。情境如下(註:此處是借鑒網路上的例子,並不是自己的實驗環境):
一夫一妻制——比如夫妻關係的兩張資料表,一個是wif表,一個是husban表,其資料表資訊如下:
CREATE TABLE `wife` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8CREATE TABLE `husband` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, `wifeid` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `fk_wife` (`wifeid`), CONSTRAINT `fk_wife` FOREIGN KEY (`wifeid`) REFERENCES `wife` (`id`)) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8
即一個wife表和一個husband表,這裡wife表為基表,husband表中的wifeid依賴於wife的主鍵id。
下面是相應的POJO:
Wife: 1.package com.linys.model; 2. 3./** 4. * Wife entity. @author MyEclipse Persistence Tools 5. */ 6. 7.public class Wife implements java.io.Serializable { 8. 9. // Fields 10. 11. /** 12. * 13. */ 14. private static final long serialVersionUID = 1L; 15. private Integer id; 16. private String name; 17. private Husband husband; 18. // Constructors 19. 20. /** default constructor */ 21. public Wife() { 22. } 23. 24. /** minimal constructor */ 25. public Wife(String name) { 26. this.name = name; 27. } 28. 29. 30. // Property accessors 31. 32. public Integer getId() { 33. return this.id; 34. } 35. 36. public void setId(Integer id) { 37. this.id = id; 38. } 39. 40. public String getName() { 41. return this.name; 42. } 43. 44. public void setName(String name) { 45. this.name = name; 46. } 47. 48. public Husband getHusband() { 49. return husband; 50. } 51. 52. public void setHusband(Husband husband) { 53. this.husband = husband; 54. } 55. 56. 57.} Husband: 1.package com.linys.model; 2. 3./** 4. * Husband entity. @author MyEclipse Persistence Tools 5. */ 6. 7.public class Husband implements java.io.Serializable { 8. 9. // Fields 10. 11. /** 12. * 13. */ 14. private static final long serialVersionUID = 1L; 15. private Integer id; 16. private Wife wife; 17. private String name; 18. 19. // Constructors 20. 21. /** default constructor */ 22. public Husband() { 23. } 24. 25. /** minimal constructor */ 26. public Husband(String name) { 27. this.name = name; 28. } 29. 30. /** full constructor */ 31. public Husband(Wife wife, String name) { 32. this.wife = wife; 33. this.name = name; 34. } 35. 36. // Property accessors 37. 38. public Integer getId() { 39. return this.id; 40. } 41. 42. public void setId(Integer id) { 43. this.id = id; 44. } 45. 46. public Wife getWife() { 47. return this.wife; 48. } 49. 50. public void setWife(Wife wife) { 51. this.wife = wife; 52. } 53. 54. public String getName() { 55. return this.name; 56. } 57. 58. public void setName(String name) { 59. this.name = name; 60. } 61. 62.}
以上是基本的資料表映射。這時候假設我們需要一對一雙向關聯,即在儲存或者更新時,可以根據一個husband執行個體可以獲得其wife執行個體,也可根據wife執行個體去獲得一個husband執行個體。
一對一雙向關聯比較特殊,不像單向關聯,在hbm設定檔中僅僅使用one-to-one配置即可,這種情況下需要使用may-to-one和one-to-one來類比一一對應,既然是一一對應,所以在many-to-one的一段,要加上unique=true屬性,從而保證其唯一性。不要問我為什麼,這是Hibernate的機制吧,其實說到這裡,我對於Hibernate還不是很瞭解,如果有大神讀到希望可以指點一二。從項目經驗來看,如果不這麼做,在同時修改了這兩個實體,然後儲存到庫中時,總是報錯,錯誤資訊為session無法同步,或者外鍵id為NULL。使用了這樣的配置後,就沒有問題了。下面看二者的設定檔:
Wife.hbm.xml Java代碼 1.<?xml version="1.0" encoding="utf-8"?> 2.<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3."http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4.<!-- 5. Mapping file autogenerated by MyEclipse Persistence Tools 6.--> 7.<hibernate-mapping> 8. <class name="com.linys.model.Wife" table="wife"> 9. <id name="id" type="java.lang.Integer"> 10. <column name="id" /> 11. <generator class="native" /> 12. </id> 13. <property name="name" type="java.lang.String"> 14. <column name="name" length="50" not-null="true" /> 15. </property> 16. <one-to-one name="husband" class="com.linys.model.Husband" property-ref="wife" cascade="all"/> 17. </class> 18.</hibernate-mapping> Husband.hbm.xml:1.<?xml version="1.0" encoding="utf-8"?> 2.<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3."http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4.<!-- 5. Mapping file autogenerated by MyEclipse Persistence Tools 6.--> 7.<hibernate-mapping> 8. <class name="com.linys.model.Husband" table="husband"> 9. <id name="id" type="java.lang.Integer"> 10. <column name="id" /> 11. <generator class="native" /> 12. </id> 13. <property name="name" type="java.lang.String"> 14. <column name="name" length="50" not-null="true" /> 15. </property> 16. <may-to-one name="wife" class="com.linys.model.Wife" fetch="select"/>17. <column name="wifeid" unique="true" not-null="true" /> 18. </many-to-one> 19. </class> 20.</hibernate-mapping>
外鍵所依賴的那個表的設定檔(wife)使用one-to-one,外鍵所在的表(husband)用many-to-one,但是要指定unique為true從而保證其唯一性。注意many這一端中的colum,配置的應該是外鍵所在表的外鍵列名,對應這裡也就是husband表中的“wifeid”,需要與資料庫中的資料表表中一致,切勿弄錯。
one-to-one:指定在Wife這個類中用於雙向關聯的屬性husband
property-ref: 在關聯對象中用於與本對象關聯的屬性。
注意:property-ref="wife"不能少,否則會造成查詢時關聯查詢失敗!
以上是實際經驗的總結,如有錯誤,歡迎指正。