两种策略:
主键关联:两个对象有相同的主键值,通过表的主键来关联
唯一外键关联:本是用于多对一的配置,若加上那个唯一的限制后,也可用来表示一对一关联关系
主键:
1、单向
情况: 一个人有一个身份证,人知道身份证,身份证不知道人(人来维护关系)
原理:让两个实体的主键一样,就不需要加入多余字段
关系图:
<span style="font-size:18px;">实体:
Card:
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;
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;
}
}
</span>
<span style="font-size:18px;">映射文件:
Card:
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.IdCard" table="t_idcard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
</class>
</hibernate-mapping>
Person:
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.Person" table="t_person">
<id name="id">
<!-- 采用foreign生成策略,forgeign会取得关联对象的标识 -->
<generator class="foreign">
<!-- property只关联对象 -->
<param name="property">idCard</param>
</generator>
</id>
<property name="name"/>
<one-to-one name="idCard" constrained="true"/>
</class>
</hibernate-mapping>
注:
使用foreign生成策略,foreign会取得对象的标识
property指关联对象
one-to-one:默认主键加载,根据对端的主键来加载关联对象
Constrained="true":当前主键(person的主键)还是一个外键参照了对端的主键(IdCard的主键),也就会生成外键约束语句
</span>
<span style="font-size:18px;">客户端:
public void testSave1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
IdCard idCard = new IdCard();
idCard.setCardNo("1111111111111111");
Person person = new Person();
person.setName("张三");
//建立关联
person.setIdCard(idCard);
//没有抛出TransientObjectException
//是由一对一关联映射的特性决定的,它必须先保存关联对象IdCard
//这样它采用foreign映射策略才能取得关联对象的标识
//也就是它默认了cascade属性
session.save(person);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
</span>
2、双向
情况:
一个人有一个身份证,人知道身份证,身份证知道人(人来维护关系)
双向就没有箭头
需要在IdCard加入<one-to-one>,指示hibernate将关联对象Person根据主键加载上来
实体:
Card:
public class IdCard {
private int id;
private String cardNo;
private Person person;
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;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
Person:
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;
}
}
映射文件:
Card:
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.IdCard" table="t_idcard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
<one-to-one name="person"/>
</class>
</hibernate-mapping>
Person:
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.Person" table="t_person">
<id name="id">
<!-- 采用foreign生成策略,forgeign会取得关联对象的标识 -->
<generator class="foreign">
<!-- property只关联对象 -->
<param name="property">idCard</param>
</generator>
</id>
<property name="name"/>
<one-to-one name="idCard" constrained="true"/>
</class>
</hibernate-mapping>
客户端:
public void testSave2() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Person person = new Person();
person.setName("张三");
IdCard idCard = new IdCard();
idCard.setCardNo("1111111111111111");
idCard.setPerson(person);
session.save(idCard);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
结果:
唯一外键
1、单向
原理:
多对一的特例,采用<many-to-one>标签来映射,指定多的一端为unique为true,这样就限制了多的一端的多重性的唯一
实体:
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;
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;
}
}
映射文件:
IdCard:
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.IdCard" table="t_idCard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/></class>
</hibernate-mapping>
Person:
<hibernate-mapping>
<class name="com.bjpowernode.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>
客户端:
public void testSave1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
IdCard idCard = new IdCard();
idCard.setCardNo("1111111111111111");
Session.save(idCard);
Person person = new Person();
person.setName("张三");
//建立关联
person.setIdCard(idCard);
//抛出TransientObjectException
//因为IdCard为Transient状态
session.save(person);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
结果:
2、双向
原理:采用<one-to-one>标签映射,必须指定<one-to-one>标签中的property-ref属性为关系字段的名称。使用单向一对一理念,idCard指定person外键关联为idCard即可
关系图:
<span style="font-size:18px;"> 实体:
IdCard:
public class IdCard {
private int id;
private String cardNo;
private Person person;
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;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
person:
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;
}
}
映射文件:
IdCard:
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.IdCard" table="t_idCard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
<one-to-one name="person" property-ref="idCard"/>
</class>
</hibernate-mapping>
Person:
<hibernate-mapping>
<class name="com.bjpowernode.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>
客户端:
public void testSave1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
IdCard idCard = new IdCard();
idCard.setCardNo("1111111111111111");
Session.save(idCard);
Person person = new Person();
person.setName("张三");
//建立关联
person.setIdCard(idCard);
//抛出TransientObjectException
//因为IdCard为Transient状态
session.save(person);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
} </span>
结果:
小结:唯一外键关联单向和双向都是一样的,都是加个外键,影响的只是对象模型