one-to-one是一对一映射关系,如人和身份证之间的关系,一个人只能有一个身份证号,一个身份证号只能属于一个人。
一对一又可分为单向映射和双向映射,映射实现可以分为主键映射和外键映射。结合一下就成了四种:
一对一单向主键映射实现思想是让一个表的主键为关联的外键,因为外键是另一个表的主键并且为一,所以可以作为主键来用。
如人和身份证的关系,人必定有一个外键关联身份证表主键,可以这个外键作为人的主键。这样就形成了人用身份证表的主键作为自己主键的特殊形式。
package com.iteedu.hibernate; public class IdCard { private int id; private String cardNo; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getCardNo() { return cardNo; } public void setCardNo(String cardNo) { this.cardNo = cardNo; } }
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.iteedu.hibernate. IdCard" table="t_idcard"> <id name="id"> <generator class="native"/> </id> <property name="cardNo"/> </class> </hibernate-mapping>
package com.iteedu.hibernate; public class Person { private int id; private String name; private IdCard idCard; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public IdCard getIdCard() { return idCard; } public void setIdCard(IdCard idCard) { this.idCard = idCard; } }
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.iteedu.hibernate.Person" table="t_person"> <id name="id"> <!-- person的主键来源idCard,也就是共享idCard的主键 --> <generator class="foreign"> <param name="property">idCard</param> </generator> </id> <property name="name"/> <one-to-one name="idCard" constrained="true"/> </class> </hibernate-mapping>
由于Person的主键为身份证的主键所以要用foreign,foreign使用另外一个相关联的对象的标识符。通常和<one-to-one>联合起来使用。
one-to-one标签的含义,指示hibernate怎么加载它的关联对象,默认根据主键加载, constrained=”true”, 表明当前主键上存在一个约束,person的主键作为外键参照了idCard。
session.beginTransaction(); IdCard idCard = new IdCard(); idCard.setCardNo("21341341234123"); Person person = new Person(); person.setName("ITEEDU"); person.setIdCard(idCard); //不会出现TransientObjectException异常 //因为一对一主键关联映射中,默认了cascade属性 session.save(person);
在IdCard中添加Person属性:
private Person person; public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; }
在配制文件中加入关联:
<one-to-one name="person"/>
这样加载card时就会加载人员信息了。
session.beginTransaction(); IdCard idCard = (IdCard)session.load(IdCard.class, 1); System.out.println("idcard.cardNo=" + idCard.getCardNo()); System.out.println("idcard.person.name=" + idCard.getPerson().getName()); session.getTransaction().commit();
一对唯一外键关联映射是多对一关联映射的特例,可以通过限制many-to-one来实现的。mang-to-one中的关联外键是可以重复的,如多个人属于一个组。如果限制其唯一性就形成了一对一关系,因为没有一个身份证id关联多个人。
采用<many-to-one>标签,指定多的一端的unique=true,这样就限制了多的一端的多重性为一。通过这种手段映射一对一唯一外键关联。
实现如下:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.iteedu.hibernate.Person" table="t_person"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <many-to-one name="idCard" unique="true"/> </class> </hibernate-mapping>
注意:主键id不能再用foreign了。
一对一唯一外键关联双向,需要在另一端(idcard),添加<one-to-one>标签,指示hibernate如何加载其关联对象,默认根据主键加载person,外键关联映射中,因为两个实体采用的是person的外键维护的关系,所以不能指定主键加载person,而要根据person的外键加载。
修改IdCard相关文件。
private Person person; public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; }
<one-to-one name="person" property-ref="idCard"/>
其中property-ref为指定关联类的属性名,这个属性将会和本类的主键相对应。如果没有指定,会使用对方关联类的主键。
注意:不是数据库中的列名,是类中的属性名。