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和它作比较找到我们要找的数据。