Hibernate一对一主键关联映射(双向关联Person<——>IDCard)。
类图:
映射的数据库表:
原理:在两端都要加上对象的引用。
Person.java:
public class Person { private Integer id; private String name; /*定义Person和IDCard的关系((双向一对一主键关联映射))*/ private IDCard idCard; public Integer getId() { return id; } public void setId(Integer 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.java:
public class IDCard { private Integer id; private String cardNo; /*IDCard和Person的关系(双向一对一主键关联映射)*/ private Person person; public Integer getId() { return id; } public void setId(Integer 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; } }
注:因为是双向关联,所以在IDCard一端要加上Person的引用,在Person一端要加上IDCard的引用。
Person.hbm.xml:
<?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 package="com.lixue.bean"> <class name="Person" table="t_person"> <id name="id"> <!-- 采用foreign生成策略,foreign回去的关联对象的标识 --> <generator class="foreign"> <!-- 通过property来表示要关联的对象 --> <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"/> </class> </hibernate-mapping>
IDCard.hbm.xml:
<?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 package="com.lixue.bean"> <class name="IDCard" table="t_idCard"> <id name="id"> <generator class="native"/> </id> <property name="cardNo"/> <!-- 声明IDCard和Person的关系 --> <one-to-one name="person"/> </class> </hibernate-mapping>
注:在IDCard一端也要加上<one-to-one>
测试通过Person添加IDCard:
public void testSave1(){ /*定义Session和事物*/ Session session = null; Transaction transaction = null; try { /*获取Session并开启事物*/ session = HibernateUtils.getSession(); transaction = session.beginTransaction(); /*创建身份证并设置属性*/ IDCard idCard = new IDCard(); idCard.setCardNo("367578677545348879"); /*创建人并设置属性*/ Person person = new Person(); person.setName("习近平"); /*建立关联*/ person.setIdCard(idCard); /*我们可以发现没有抛出TransientObjectException * 这不科学啊,我们并没有保存IDCard对象,它还是Transient状态啊, * 怎么可能不保存呢?其实这是由一对一关联映射的特性决定的,它必须先 * 保存关联对象Idcard,这样它采用foreign映射策略才能取得对象的标识 * 也就默认了cascade属性所导致的 */ session.save(person); /*提交事物*/ transaction.commit(); } catch (Exception e) { e.printStackTrace(); transaction.rollback(); } finally{ HibernateUtils.closeSession(session); } }
注:这样是可以实现级联保存的,因为Person是维护关系的一端。
测试通过IDCard添加Person:
public void testSave2(){ /*定义Session和事物*/ Session session = null; Transaction transaction = null; try { /*获取Session并开启事物*/ session = HibernateUtils.getSession(); transaction = session.beginTransaction(); /*创建人并设置属性*/ Person person = new Person(); person.setName("李克强"); /*创建身份证并设置属性*/ IDCard idCard = new IDCard(); idCard.setCardNo("123578677545348879"); /*建立关联*/ idCard.setPerson(person); /*我们可以发现没有抛出TransientObjectException *但是也不会保存Person的对象,因为IDCard端的one-to-one不影响存储,只影响加载 */ session.save(idCard); /*提交事物*/ transaction.commit(); } catch (Exception e) { e.printStackTrace(); transaction.rollback(); } finally{ HibernateUtils.closeSession(session); } }
注:通过IDCard是不能级联保存Person的,因为IDCard是关系的被维护端。
测试通过Person加载IDCard:
public void testFind(){ /*获取Person对象*/ Person person = (Person) HibernateUtils.getSession().get(Person.class, 1); /*获取Person的name属性*/ System.out.println("person.name=" + person.getName()); /*获取Person关联的IDCard的idcardNo*/ System.out.println("person.idCard.idCardNo=" + person.getIdCard().getCardNo()); }
注:通过Person可以加载IDCard对象,因为是双向关联(发出两条sql语句)。
测试通过IDCard添加Person:
public void testFind2(){ /*获取Person对象*/ IDCard idCard = (IDCard) HibernateUtils.getSession().get(IDCard.class, 1); /*获取Person的name属性*/ System.out.println("idCard.name=" + idCard.getCardNo()); /*获取Person关联的IDCard的idcardNo*/ System.out.println("idCard.person.name=" + idCard.getPerson().getName()); }
注:通过IDCard可以加载Person对象,因为是双向关联(只发出一条语句,这涉及到抓取策略,以后会详解)