009一对一 主键关联映射_单向(one-to-one)
009一对一 主键关联映射_单向(one-to-one)
² 两个对象之间是一对一的关系,如Person-IdCard(人—身份证号)
² 有两种策略可以实现一对一的关联映射
- 主键关联:即让两个对象具有相同的主键值,以表明它们之间的一一对应的关系;数据库表不会有额外的字段来维护它们之间的关系,仅通过表的主键来关联。
- 唯一外键关联:外键关联,本来是用于多对一的配置,但是如果加上唯一的限制之后,也可以用来表示一对一关联关系。
实例场景:人—-> 身份证号(PersonàIdCard),从IdCard看不到Person对象
对象模型(主键关联映射-单向):
(站在人的角度看)
IdCard实体类:
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; } }
Person实体类:
public class Person { private int id; private String name; private IdCard 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; } }
因为是person引用idcard,所以idcard要求先有值。而person的主键值不是自己生成的。而是参考idcard的值,person即是主键,同时也是外键。
IdCard实体类的映射文件:
<hibernate-mapping> <class name="com.wjt276.hibernate.IdCard" table="t_idcard"> <id name="id" column="id"> <generator class="native"/> </id> <property name="cardNo"/> </class> </hibernate-mapping>
Persion实体类的映射文件:
<hibernate-mapping> <class name="com.wjt276.hibernate.Person" table="t_person"> <id name="id" column="id"> <!-- 因为主键不是自己生成的,而是作为一个外键(来源于其它值),所以使用foreign生成策略 foreign:使用另外一个相关联的对象的标识符,通常和<one-to-one>联合起来使用。 再使用元素<param>的属性值指定相关联对象(这里Person相关联的对象为idCard,则标识符为idCard的id)为了能够在加载person数据同时加载IdCard数据,所以需要使用一个标签<one-to-one>来设置这个功能。 --> <generator class="foreign"> <!-- 元素<param>属性name的值是固定为property --> <param name="property">idCard</param> </generator> </id> <property name="name"/> <!-- <one-to-one>标签 表示如何加载它的引用对象(这里引用对象就指idCard这里的name值是idCard),同时也说是一对一的关系。 默认方式是根据主键加载(把person中的主键取出再到IdCard中来取相关IdCard数据。) 我们也说过此主键也作为一个外键引用 了IdCard,所以需要加一个数据库限制(外键约束)constrained="true" --> <one-to-one name="idCard" constrained="true"/> </class> </hibernate-mapping>
导出至数据库表生成代码如下:
create table t_idcard (id integer not null auto_increment, cardNo varchar(255), primary key (id)) create table t_person (id integer not null, name varchar(255), primary key (id)) alter table t_person add index FK785BED805248EF3 (id), add constraint FK785BED805248EF3 foreign key (id) references t_idcard (id) * alter table …… 意思:person的主键id以外键参照idcard的主键 |
※<one-to-one>标签※
现在是使用一对一主键关联映射,因为主键不是自己生成的,而是作为一个外键(来源于其它值),所以使用foreign生成策略(使用另外一个相关联的对象的标识符,通常和<one-to-one>联合起来使用)。再使用元素<param>的属性值指定相关联对象(这里Person相关联的对象为idCard,则标识符为idCard的id)为了能够在加载person数据同时加载IdCard数据,所以需要使用一个标签<one-to-one>来设置这个功能。
<id name="id" column="id"> <generator class="foreign"> <param name="property">idCard</param> </generator> </id> <one-to-one name="idCard" constrained="true"/>
一对一 主键关联映射 存储测试
session = HibernateUtils.getSession(); tx = session.beginTransaction(); IdCard idCard = new IdCard(); idCard.setCardNo("88888888888888888888888"); Person person = new Person(); person.setName("菜10"); person.setIdCard(idCard); //不会出现TransientObjectException异常 //因为一对一主键关键映射中,默认了cascade属性。 session.save(person); tx.commit();
注:不会出现TransientObjectException异常,因为一对一主键关键映射中,默认了cascade属性。
生成SQL语句:
Hibernate: insert into t_idcard (cardNo) values (?) Hibernate: insert into t_person (name, id) values (?, ?) |
一对一 主键关联映射 加载测试
session = HibernateUtils.getSession(); tx = session.beginTransaction(); Person person = (Person)session.load(Person.class, 1); System.out.println("person.name=" + person.getName()); System.out.println("idCard.cardNo=" + person.getIdCard().getCardNo()); // 提交事务 tx.commit();
生成SQL语句:
Hibernate: select person0_.id as id0_0_, person0_.name as name0_0_ from t_person person0_ where person0_.id=? person.name=菜10 Hibernate: select idcard0_.id as id1_0_, idcard0_.cardNo as cardNo1_0_ from t_idcard idcard0_ where idcard0_.id=? idCard.cardNo=88888888888888888888888 |
一对一 主键关联映射 总结:
让两个实体对象的ID保持相同,这样可以避免多余的字段被创建
<id name="id" column="id"> <!—person的主键来源idcard,也就是共享idCard的主键--> <generator class="foreign"> <param name="property">idCard</param> </generator> </id> <property name="name"/> <!—one-to-one标签的含义:指示hibernate怎么加载它的关联对象,默认根据主键加载 constrained="true",表面当前主键上存在一个约束:person的主键作为外键参照了idCard--> <one-to-one name="idCard" constrained="true"/>