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=utf8 CREATE 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"不能少,否则会造成查询时关联查询失败!
以上是实际经验的总结,如有错误,欢迎指正。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。