Hibernate一对一主键关联映射(单向关联Person——>IDCard即通过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,所以在Person中要添加IDCard的引用。
IDCard.java:
public class IDCard { private Integer id; private String cardNo; 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; } }
注:因为是单向关联,且从IDCard不能关联到Person,所以IDCard只是一个普通的javaBean,不需要添加任何对象的引用。
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>
注:单向一对一主键关联映射,原理是让两个实体的主键保持一致,也就是说,类的主键生成策略要改为foreign,其他解释见注释。
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"/> </class> </hibernate-mapping>
注:IDCard是一个普通的javaBean,所以它的映射文件非常简单。
测试添加:
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); } }
注:单向一对一主键关联映射,默认是cascade级联操作的,这就是为什么我们不需要显示的保存IDCard对象,也可以保存Person。
测试查询:
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的属性。