Hibernate学习笔记9--关联关系之一对一

关联关系之一对一(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

实体关联关系:

http://blog.csdn.net/imust_can/article/details/7062038

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值