hibernate 一对一 和 N-1
Hibernate 一对一外键单向关联
事实上,单向1-1与N-1的实质是相同的,1-1是N-1的特例,单向1-1与N-1的映射配置也非常相似。只需要将原来的many-to-one元素增加unique="true"属性,用于表示N的一端也必须是唯一的,在N的一端增加了唯一的约束,即成为单向1-1。基于外键的单向1-1的配置将与无连接表N-1关联的many-to-one增加unique="true"属性即可。
one-to-one 不会加载字段,它告诉HIBERNATE 怎样加载其引用对象.如何加载呢,默认根据 主键加载其引用对象.如在t_person 中查到id=2,自动加载t_idCard 中id=2的对象信息. constrained="true",表明person主键是个外键,表示当前主键上存在着idCard约束,当 前主键id作为外键,参照了idCard.
大家都知道hibernate中的one-to-one映射主要有两种策略,(1)一对一主键关联(单向和双向)。(2)一对一外键映射(单项和双向)。本文主要讲解一下,一对一外键映射中的双向问题,在此前先通过一个实例了解。
person和idCard,是一种一对一的关系,其中
t_person表
idnameidCard(unique)
1张三
2王五1
其中王五是没有idcard,这也符合现实中的,有些人是没有身份证的。
t_idCard表
idcardNo
111111111111111
实体类:
IdCard
package com.bjpowernode.hibernate; public class IdCard { private int id; private String cardNo; private Person person; public Person getPerson() { return person; } public void setPerson(Person person) { this.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; } }
Person
package com.bjpowernode.hibernate; 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; } }
(3)配置文件
IdCard的:
<?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.bjpowernode.hibernate"> <class name="IdCard" table="t_idCard"> <id name="id"> <generator class="native"/> </id> <property name="cardNo"/> <one-to-one name="person" class="Person" /> </class> </hibernate-mapping>
Person的:
<?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.bjpowernode.hibernate"> <class name="Person" table="t_person"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <many-to-one name="idCard" cascade="all"class="IdCard" unique="true" column="card_ID" /> </class> </hibernate-mapping>
(3)
向t_person中插入数据:
import org.hibernate.Session; import junit.framework.TestCase; public class One2OneTest extends TestCase { public void testSave1() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Person person = new Person(); person.setName("张三"); session.save(person); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } }
结果如下:
mysql>select*fromt_person;
+----+------+---------+
|id|name|card_ID|
+----+------+---------+
|1|张三|NULL|
+----+------+---------+
1rowinset(0.00sec)
mysql>select*fromt_idcard;
Emptyset(0.00sec)
在插入数据:
public void testSave2() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); IdCard idCard = new IdCard(); idCard.setCardNo("1111111111"); session.save(idCard); Person person = new Person(); person.setName("王五"); //建立关联 person.setIdCard(idCard); session.save(person); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } }
数据库中的结果如下:
mysql>select*fromt_person;
+----+------+---------+
|id|name|card_ID|
+----+------+---------+
|1|张三|NULL|
|2|王五|1|
+----+------+---------+
2rowsinset(0.00sec)
mysql>select*fromt_idcard;
+----+------------+
|id|cardNo|
+----+------------+
|1|1111111111|
+----+------------+
1rowinset(0.00sec)
(4)加载数据,这样的话就可以从person的一端加载到idCard,
如下:
public void testLoad1() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Person person = (Person)session.load(Person.class, 2); System.out.println("person.name=" + person.getName()); System.out.println("person.cardNo="+ person.getIdCard().getCardNo()); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } }
结果如下:
Hibernate:selectperson0_.idasid0_0_,person0_.nameasname0_0_,person0_.card_IDascard3_0_0_fromt_personperson0_whereperson0_.id=?
person.name=王五
Hibernate:selectidcard0_.idasid1_1_,idcard0_.cardNoascardNo1_1_,person1_.idasid0_0_,person1_.nameasname0_0_,person1_.card_IDascard3_0_0_fromt_idCardidcard0_leftouterjoint_personperson1_onidcard0_.id=person1_.idwhereidcard0_.id=?
person.cardNo=1111111111这样的就找到了person对应的idcard,那能不能有idCard找到person呢?
public void testLoad2() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); // IdCard idCard = (IdCard)session.load(IdCard.class, 1); System.out.println("idCard.cardNo=" + idCard.getCardNo()); System.out.println("idCard.person.name=" +idCard.getPerson().getName()); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } }
结果如下:
Hibernate:selectidcard0_.idasid1_1_,idcard0_.cardNoascardNo1_1_,person1_.idasid0_0_,person1_.nameasname0_0_,person1_.card_IDascard3_0_0_fromt_idCardidcard0_leftouterjoint_personperson1_onidcard0_.id=person1_.idwhereidcard0_.id=?
idCard.cardNo=1111111111
idCard.person.name=张三
结果对吗?
肯定不对,idCard.cardNo=1111111111这是王五的idCard,怎么查出来张三的呢?原因在于:
idCard的配置文件问题:
应该在idCard的配置文件的<one-to-onename="person"class="Person"/>
修改为<one-to-onename="person"class="Person"property-ref="idCard"/>
因为:如果不修改则idCard会根据自己的id和person中的id比较(因为one-to-one是通过id查找到的),这样是不符合要求的,因为我们t_idcard中的id和t_person中Card_ID相比较,这样的话可以通过
property-ref="idCard" 的设置找到t_person表中Card_ID和它作比较找到我们要找的数据。