关联关系之一对一(Person--IdCard)
一、第一种实现方式(主键关联):
一对一关系(Person-idCard):分成主对象和从对象(主从关系)
Person主对象(更重要一些),idCard从对象
让person的id等于idCard的id,所以id既是主键又是外键
废话不多说,上代码
Person.java
package cn.itcast.domain;
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;
}
}
IdCarD.java
package cn.itcast.domain;
import java.util.Date;
public class IdCard {
private int id;
private Date usefulLife;//使用期限
private Person person;//有个复杂的属性
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getUsefulLife() {
return usefulLife;
}
public void setUsefulLife(Date usefulLife) {
this.usefulLife = usefulLife;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
计划全在映射文件
Person.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.domain">
<class name="Person" >
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name" />
<!-- 表示一对一的关系 :对idCard属性经行映射-->
<one-to-one name="idCard" ></one-to-one>
</class>
</hibernate-mapping>
IdCard.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.domain">
<class name="IdCard" table="id_Card">
<!-- 对象标示符,类型可以不写,hibernate自己识别 -->
<id name="id" column="id">
<!-- 指定主键生成方式。
native根据方言判定生成主键的方式
-->
<generator class="foreign">
<!-- id通过一个外键数据获得 -->
<param name="property">person</param>
</generator>
</id>
<property name="usefulLife" column="useful_Life" />
<!-- 表示一对一的关系 :对person属性进行映射。constrained="true" 添加约束,让id有外键关联-->
<one-to-one name="person" constrained="true"></one-to-one>
</class>
</hibernate-mapping>
配置文件:
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory >
<property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:ORCL</property>
<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property><!-- 方言 -->
<property name="hibernate.connection.username">websb</property>
<property name="hibernate.connection.password">ddit</property>
<property name="hibernate.hbm2ddl.auto">create</property><!-- 自动创建表 -->
<property name="show_sql">true</property><!-- 显示sql -->
<mapping resource="cn/itcast/domain/User.hbm.xml"/>
<mapping resource="cn/itcast/domain/Employee.hbm.xml"/> <!-- 一对多模型 -->
<mapping resource="cn/itcast/domain/Department.hbm.xml"/>
<mapping resource="cn/itcast/domain/Person.hbm.xml"/> <!-- 一对一模型 -->
<mapping resource="cn/itcast/domain/IdCard.hbm.xml"/>
</session-factory>
</hibernate-configuration>
测试类:
package cn.itcast.RelationalMapping;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.Transaction;
import cn.itcast.dao.HibernateUtil;
import cn.itcast.domain.IdCard;
import cn.itcast.domain.Person;
/**
* 一对一测试类
*/
public class One2One {
public static void main(String[] args) {
add();
}
static Person add(){
Session s = null;
Transaction tx = null;
try {
s=HibernateUtil.getSession();
IdCard idCard = new IdCard();
idCard.setUsefulLife(new Date());
Person p = new Person();
p.setName("p1");
p.setIdCard(idCard);//告诉这个人是什么身份证号
idCard.setPerson(p);//告诉这个身份证号是属于那个人的
tx=s.beginTransaction();
s.save(p);
s.save(idCard);
tx.commit();
return p;
} finally {
if(s!=null){
s.close();
}
}
}
}
分析:
一对一关系(Person-idCard):分成主对象和从对象(主从关系)
Person主对象(更重要一些),idCard从对象
让person的id等于idCard的id,所以id既是主键又是外键
如果主对象不存在,则从对象也保存失败
发现一对一关系中
p.setIdCard(idCard);
idCard.setPerson(p);
相互都设置了关联,但是去掉第一行代码,程序仍能正常运行,而相反删去第二行代码,程序报错。
是存在主从表关系,可以仅保存主对象,但是不可以只保存从对象不保存主对象。
练习时报的错:
INFO: HHH000041: Configured SessionFactory: null
Exception in thread "main" java.lang.NoClassDefFoundError: cn/itcast/domain/idCard (wrong name: cn/itcast/domain/IdCard)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:621)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
at java.net.URLClassLoader.access$000(URLClassLoader.java:56)
at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:169)
at org.hibernate.internal.util.ReflectHelper.classForName(ReflectHelper.java:192)
at org.hibernate.internal.util.ReflectHelper.reflectedPropertyClass(ReflectHelper.java:228)
at org.hibernate.mapping.SimpleValue.setTypeUsingReflection(SimpleValue.java:324)
at org.hibernate.cfg.HbmBinder.bindSimpleId(HbmBinder.java:449)
at org.hibernate.cfg.HbmBinder.bindRootPersistentClassCommonValues(HbmBinder.java:382)
at org.hibernate.cfg.HbmBinder.bindRootClass(HbmBinder.java:322)
at org.hibernate.cfg.HbmBinder.bindRoot(HbmBinder.java:173)
at org.hibernate.cfg.Configuration$MetadataSourceQueue.processHbmXml(Configuration.java:3437)
at org.hibernate.cfg.Configuration$MetadataSourceQueue.processHbmXmlQueue(Configuration.java:3429)
at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3417)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1348)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1747)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1798)
at cn.itcast.dao.HibernateUtil.<clinit>(HibernateUtil.java:37)
at cn.itcast.RelationalMapping.One2One.add(One2One.java:26)
at cn.itcast.RelationalMapping.One2One.main(One2One.java:19)
经过分析发现是IdCard.hbm.xml的映射文件写错了!下回注意 !
错误:<class name="idCard" table="id_Card">
正确:<class name="IdCard" table="id_Card">
二、查询
(1)获取主对象能否查询出从对象
查询主对象时,通过一次查询,使用左外连接,将从对象数据查出来:
Hibernate: select
person0_.id as id1_2_1_,
person0_.name as name2_2_1_,
idcard1_.id as id1_3_0_,
idcard1_.useful_Life as useful2_3_0_
from
Person person0_,
id_Card idcard1_
where
person0_.id=idcard1_.id(+)
and person0_.id=?
/**
* 查询主对象
* @param id
* @return
*/
static Person queryPerson(int id){
Session s = null;
Transaction tx = null;
try {
s=HibernateUtil.getSession();
tx=s.beginTransaction();
Person p = (Person)s.get(Person.class, id);
System.out.println(p.getIdCard().getUsefulLife());
tx.commit();
return p;
} finally {
if(s!=null){
s.close();
}
}
}
(2)获取从对象能否查询出主对象
查询从对象时,通过两次查询,先查从对象,之后使用左外连接,将从主象数据查出来
但这是如果注释掉System.out.println(p.getIdCard().getUsefulLife());则主对象将不会被查询。只查询一次。
这里涉及懒加载的问题,后续章节会详解。
Hibernate:
select
idcard0_.id as id1_3_0_,
idcard0_.useful_Life as useful2_3_0_
from
id_Card idcard0_
where
idcard0_.id=?
Hibernate:
select
person0_.id as id1_2_1_,
person0_.name as name2_2_1_,
idcard1_.id as id1_3_0_,
idcard1_.useful_Life as useful2_3_0_
from
Person person0_,
id_Card idcard1_
where
person0_.id=idcard1_.id(+)
and person0_.id=?
/**
* 查询从对象
* @param id
* @return
*/
static IdCard queryIdCard(int id){
Session s = null;
Transaction tx = null;
try {
s=HibernateUtil.getSession();
tx=s.beginTransaction();
IdCard idCard = (IdCard)s.get(IdCard.class, id);
System.out.println(idCard.getPerson().getName());
tx.commit();
return idCard;
} finally {
if(s!=null){
s.close();
}
}
}
三、一对一第二种实现方式(外键关联)
在id_card表有自己的主键列,自己自增长,另外添加一字段person_id与person表中的id关联。
此时两表的关系近似于一对多,使用满足一对多的数据也可插入ID_card表中。
解决:为了实现一对一,我们在IDcard的映射文件中,对于外键的引用我们添加唯一性约束。
IdCard.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.domain">
<class name="IdCard" table="id_Card">
<!-- 对象标示符,类型可以不写,hibernate自己识别 -->
<id name="id" column="id">
<!-- 指定主键生成方式。native根据方言判定生成主键的方式 -->
<generator class="native"/>
</id>
<property name="usefulLife" column="useful_Life" />
<!-- 此时关联关系近乎于多对一,添加 unique唯一性约束,以满足一对一 -->
<many-to-one name="person" column="person_id" unique="true"></many-to-one>
</class>
</hibernate-mapping>
Person.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.domain">
<class name="Person" >
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name" />
<!-- 表示一对一的关系 :对idCard属性经行映射-->
<one-to-one name="idCard" property-ref="person" ></one-to-one>
</class>
</hibernate-mapping>
由此实现双向关联。
扩展:
property-ref属性介绍:
http://blog.csdn.net/fengyuanfa/article/details/5096764
实体关联关系: