一对一关联包括两种类型:
1.主键关联
2.惟一外键关联
主键关联:
两张关联表通过主键形成一对一映射关系
实例:一个公民对应一个身份证
1.主键关联
实体类
TUser .java
/** * 主键关联 * */ public class TUser implements Serializable { private static final long serialVersionUID = -133439792227297972L; private Integer id; private Integer age; private String name; private TPassport passport; .......................... }
TPassport.java
/** * 主键关联 * */ public class TPassport implements Serializable{ private static final long serialVersionUID = -2207892280100301351L; private Integer id; private String serial; private Integer expiry; private TUser user; }
配置文件
Tuser.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" > <!-- 主键关联 --> <hibernate-mapping> <class name="com.model.TUser" table="t_user" dynamic-update="true" > <id name="id" type="java.lang.Integer" column="id" unsaved-value="0" > <generator class="native" /> </id> <property name="name" column="name" type="string"/> <property name="age" column="age" type="java.lang.Integer"/> <one-to-one name="passport" class="com.model.TPassport" cascade="all" outer-join="false"/> </class> </hibernate-mapping>
Tpassport.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" > <!-- 主键关联 --> <hibernate-mapping> <class name="com.model.TPassport" table="t_passport" dynamic-update="true" > <id name="id" type="java.lang.Integer" column="id" unsaved-value="0" > <!-- 由于采用了主键关联方式,那么通过主键关联的两张表,其关联记录的主键值必须保持同步。 这也就意味着,我们只需为一张表设定主键生成策略,而另一张表的主键与之共享相同的主键值 通过“foreign”类型的主键生成策略与外键共享主键值 --> <generator class="foreign"> <param name="property">user</param> </generator> </id> <property name="serial" column="serial" type="string"/> <property name="expiry" column="expiry" type="java.lang.Integer"/> <!-- constrained必须是“true”,以告知hibernate当前表主键上存在一个约束:t_passport表引用了t_user表的主键 --> <one-to-one name="user" class="com.model.TUser" constrained="true"/> </class> </hibernate-mapping>
测试代码(部分)
//主键关联 public void testSave() { TUser user = new TUser(); user.setName("zhangsan"); user.setAge(20); TPassport passport = new TPassport(); passport.setExpiry(445555); passport.setSerial("PCN2324"); // 设置相互关联 passport.setUser(user); user.setPassport(passport); try { Transaction tx = session.beginTransaction(); // 由于TUser类的one-to-one节点被设置为cascade=all,其关联的passport对象将被级联保存 session.save(user); tx.commit(); } catch (HibernateException e) { e.printStackTrace(); } } //主键关联 public void testLoad1() { try { TUser user = (TUser) session.load(TUser.class, 1); System.out.println("user name---->" + user.getName()); System.out.println("passport serial---->" + user.getPassport().getSerial()); } catch (HibernateException e) { e.printStackTrace(); } /** out-join="true" 加载TUser实例时 hibernate通过left outer join将t_user表及其关联的t_group表同时读出 * Hibernate: select tuser0_.id as id1_, tuser0_.name as name1_, * tuser0_.age as age1_, tpassport1_.id as id0_, tpassport1_.serial as * serial0_, tpassport1_.expiry as expiry0_ from t_user tuser0_ * left outer join * t_passport tpassport1_ on tuser0_.id=tpassport1_.id where tuser0_.id=? */ } //主键关联 public void testLoad2() { try { TUser user = (TUser) session.load(TUser.class, 1); System.out.println("user name---->" + user.getName()); System.out.println("passport serial---->" + user.getPassport().getSerial()); } catch (HibernateException e) { e.printStackTrace(); } /** one-to-one节点设定为 out-join="false"时,分别读取 * Hibernate: select tuser0_.id as id0_, tuser0_.name as name0_, tuser0_.age as age0_ from t_user tuser0_ where tuser0_.id=? * Hibernate: select tpassport0_.id as id1_, tpassport0_.serial as serial1_, tpassport0_.expiry as expiry1_, tuser1_.id as id0_, tuser1_.name as name0_, tuser1_.age as age0_ from t_passport tpassport0_ left outer join t_user tuser1_ on tpassport0_.id=tuser1_.id where tpassport0_.id=? */ }
2.惟一外键关联
实体类
TGroup.java
/** * 惟一外键关联实体 */ public class TGroup implements Serializable { private static final long serialVersionUID = 263676571059714064L; private Integer id; private String name; // 不加实现的是单向一对一关系 通过Tuser2对象可以获得其相对应的Tgroup对象,但不能反过来 // 增加是为了实现双向一对一关系 可以互相获得 并且还要在TGroup.cfg.xml中追加one-to-one配置 private TUser2 user; ............................. }
TUser2.java
/** *惟一外键关联实体 */ public class TUser2 implements Serializable{ private static final long serialVersionUID = -1898408468538505300L; private Integer id; private Integer age; private String name; private TGroup group; .................. }
配置文件
TGroup.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" > <hibernate-mapping> <class name="com.model.TGroup" table="t_group" dynamic-update="true" > <id name="id" type="java.lang.Integer" column="id" unsaved-value="0" > <generator class="native" /> </id> <property name="name" column="name" type="string"/> <one-to-one name="user" class="com.model.TUser2" property-ref="group"/> </class> </hibernate-mapping>
Tuser2.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" > <hibernate-mapping> <class name="com.model.TUser2" table="t_user2" dynamic-update="true" > <id name="id" type="java.lang.Integer" column="id" unsaved-value="0" > <generator class="native" /> </id> <property name="name" column="name" type="string"/> <property name="age" column="age" type="java.lang.Integer"/> <!-- 惟一外键关联的一对一关系只是多对一关系的一个特例而已 --> <many-to-one name="group" class="com.model.TGroup" column="group_id" unique="true"/> </class> </hibernate-mapping>
测试代码(部分)
public void testSave2(){ TGroup group=new TGroup(); group.setName("group-one"); TUser2 user=new TUser2(); user.setName("lisi"); user.setAge(20); user.setGroup(group); try { Transaction tx=session.beginTransaction(); session.save(user); session.save(group); //必须保存 但先后顺序不要求 tx.commit(); } catch (HibernateException e) { e.printStackTrace(); } } //单向 user---->group public void testLoad3(){ try { TUser2 user=(TUser2) session.load(TUser2.class, 1); System.out.println("group name--->"+user.getGroup().getName()); } catch (HibernateException e) { e.printStackTrace(); } } //双向 group-->user public void testLoad4(){ /** * 在TGroup.cfg.xml中不添加one-to-one配置时,查不到user信息 * Hibernate: select tgroup0_.id as id0_, tgroup0_.name as name0_ from t_group tgroup0_ where tgroup0_.id=? Group name---->group-one */ try { TGroup group=(TGroup) session.load(TGroup.class, 1); System.out.println("Group name---->"+group.getName()); System.out.println("group user---->"+group.getUser().getName()); } catch (HibernateException e) { e.printStackTrace(); } /** 添加配置后 * Hibernate: select tgroup0_.id as id1_, tgroup0_.name as name1_, tuser21_.id as id0_, tuser21_.name as name0_, tuser21_.age as age0_, tuser21_.group_id as group_id0_ from t_group tgroup0_ left outer join t_user2 tuser21_ on tgroup0_.id=tuser21_.group_id where tgroup0_.id=? Hibernate: select tuser20_.id as id1_, tuser20_.name as name1_, tuser20_.age as age1_, tuser20_.group_id as group_id1_, tgroup1_.id as id0_, tgroup1_.name as name0_ from t_user2 tuser20_ left outer join t_group tgroup1_ on tuser20_.group_id=tgroup1_.id where tuser20_.group_id=? Group name---->group-one group user---->lisi */ }