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

关系映射
.多对一(Employee-Department)
1.建表示在员工表中添加一个外键
表示Employee-Department之间的多对一的关系,可以在Employee中建一个departid字段。
缺点:想知道部门信息还得现查一遍
解决:是在Employee类中建一个Department类型的成员变量,这才体现出面向对象的感觉

分析:hibernate不是单纯的把column="depart_id"赋值给name="depart" ,而是hibernate会根据这个一对多的关系反射找到Department这个类,之后定位到相应的映射文件,将Department表的数据查出来,经行封装赋值。数据会根据主外键寻找取出。
pk:主键
fk:外键

<?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="Employee">
		<!-- 对象标示符,类型可以不写,hibernate自己识别 -->
		<id name="id" column="id">
			<!-- 指定主键生成方式。
        native根据方言判定生成主键的方式
         -->
			 <generator class="native"/> 
		</id>
		
		<property name="name" column="name" unique="true" not-null="true"/><!--标示name唯一性,非空的限制 -->
		<!-- private Department depart是一个复杂的属性,所以不能用 property映射-->
		<!--Employee类中Department的对象名  -->
		<many-to-one name="depart" column="depart_id" not-null="true" ></many-to-one>
	</class>
	

</hibernate-mapping>



2.缺省映射的(什么都不给):
就是一个对象的外键,必定是另一个表的主键。
如果不是就得添加一个属性引用, property-ref=“关联表字段”

如:

<many-to-one name="depart" column="depart_id" not-null="true"  property-ref=“name”></many-to-one>

解释:depart_id对应另一个表(实体)的name
一般我们不使用,以为这是一种数据库不良的设置,为了避免这种情况我们才添加了这个没有什么用处的id列


3.以下是剩余代码

员工类:

注意:为了实现多对一的关联关系,添加private Department depart对象

package cn.itcast.domain;
/**
 * 员工类
 * 
 * @author Mars
 *
 */
public class Employee {
 private int id;
 private String name;
 private Department depart;
 public int getId() {
  return id;
 }
 public Department getDepart() {
  return depart;
 }
 public void setDepart(Department depart) {
  this.depart = depart;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
}

部门类:


 

package cn.itcast.domain;
/**
 * 部门类
 * @author Mars
 *
 */
public class Department {
	private int id;
	private String name;
	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;
	}
	
}


映射文件:

<?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="Department" >
		<!-- 对象标示符,类型可以不写,hibernate自己识别 -->
		<id name="id" column="id">
			<!-- 指定主键生成方式。
        native根据方言判定生成主键的方式
         -->
			 <generator class="native"/> 
		</id>
		
		<property name="name" column="name" unique="true" not-null="true"/><!--标示name唯一性,非空的限制 -->
		
	</class>


</hibernate-mapping>


工具类:

管理session

package cn.itcast.dao;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/**
 *(1)不想让其他类继承工具类
 *(2)不能让它创建对象,所以属性全部private,还得有个private的无参数构造
 * @author Mars
 *
 */
public final class HibernateUtil {
	private static SessionFactory sessionFactory;
	
	private HibernateUtil(){
		
	}
	/**
	 * 细节1:Configuration:是一个配置类
	 * Configuration的对象会找hibernate.cfg.xml,完成hibernate的初始化
	 *
	 * 细节2:hibernate的配置文件有两种hibernate.cfg.xml和hibernate.properties
	 * 两种存在一种即可,当然如果都存在的话,hibernate.cfg.xml中的配置信息会覆盖hibernate.properties的配置信息
	 * 
	 * 细节3:初始化工作只尽量只初始化一次,耗时
	 */
	static{
		//1。读取并解析配置文件
		Configuration cfg = new Configuration();
		//如果hibernate.cfg.xml不是放在类路径下,就需要此时指定路径
		//cfg.configure("filename");
		cfg.configure();
		//可以使用代码来设置配置信息,但是不便于管理,不建议使用
		//cfg.setProperty("hibernate.connection.driver_class", "oracle.jdbc.driver.OracleDriver");
		//2。读取并解析映射信息,创建SessionFactory
		//所有的配置信息都可以在SessionFactory中找到,映射文件的信息都能找到
		sessionFactory = cfg.buildSessionFactory();
	}
	/**
	 * 获取session
	 * @return
	 */
	public static Session getSession(){
		//	3。打开Session
		return sessionFactory.openSession();
	}
	
	/**
	 * 获取SessionFactory对象
	 * @return
	 */
	public static SessionFactory getSessionFactory(){
		return sessionFactory;
	}
}


测试类:

package cn.itcast.RelationalMapping;

import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;

import cn.itcast.dao.HibernateUtil;
import cn.itcast.domain.Department;
import cn.itcast.domain.Employee;

public class Many2one {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Department dept = add();
		Employee emp =query(1);
		//外面使用牵扯到懒加载,可在查询方法中添加代理初始化
		System.out.println("deoart name:"+emp.getDepart().getName());
		
	}
	static Employee query(int empId){
		Session s = null;
		Transaction tx =null;
		try {
			s=HibernateUtil.getSession();
			tx=s.beginTransaction();
			Employee emp = (Employee)s.get(Employee.class, empId);
			//查询分成两步:1.先查询雇员的
			//             2.之后按照dept_id查询部门信息
			//如果一开始我们将Employee中的部门设成int类型的dept_id,则部门信息就得手工完成,现在由部门信息完成,代码简洁很多
//			System.out.println("deoart name:"+emp.getDepart().getName());
			//代理初始化,涉及懒加载
			Hibernate.initialize(emp.getDepart());
			return emp;
		} finally{
			if(s!=null){
				s.close();
			}
		}
	}
	/**
	 * 多对一添加方法
	 * @return
	 */
	static Department add(){
		Session s = null;
		Transaction tx =null;
		
		try {
			Department depart = new Department();
			depart.setName("depart name");
			Employee  emp = new Employee();
			emp.setDepart(depart);//对象模型,建立两个对象的关联
			emp.setName("emp name");
			s=HibernateUtil.getSession();
			tx=s.beginTransaction();
			s.save(emp);
			s.save(depart);
			tx.commit();
			return depart;
		} finally{
			if(s!=null){
				s.close();
			}
		}
	}
}


 

 

4.编写时遇到的异常:
Exception in thread "main" org.hibernate.MappingException: Unknown entity: cn.itcast.domain.Department
 at org.hibernate.internal.SessionFactoryImpl.getEntityPersister(SessionFactoryImpl.java:1141)
 at org.hibernate.internal.SessionImpl.getEntityPersister(SessionImpl.java:1433)
 at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:116)
 at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:206)
 at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:55)
 at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:191)
 at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:49)
 at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
 at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:764)
 at org.hibernate.internal.SessionImpl.save(SessionImpl.java:756)
 at org.hibernate.internal.SessionImpl.save(SessionImpl.java:752)
 at cn.itcast.RelationalMapping.Many2one.add(Many2one.java:31)
 at cn.itcast.RelationalMapping.Many2one.main(Many2one.java:16)
分析:在hibernate.cfg.xml中没有配置相应的映射xml


5.疑问:
 s.save(depart);
 s.save(emp);
 如果将这句颠倒,会保存成功?
猜想:不会成功,保存emp时会由于找不到相应的dept主键,保存不成功
结果与分析:结果成功了
hibernate的执行是这样的Hibernate:
    insert
    into
        Employee
        (name, depart_id, id)
    values
        (?, ?, ?)
Hibernate:
    insert
    into
        Department
        (name, id)
    values
        (?, ?)
Hibernate:
    update
        Employee
    set
        name=?,
        depart_id=?
    where
        id=?
       
先向emp中插入一个dept_id=null的记录,之后检测到相应的dept_id,再执行一个update语句。
本质上:hibernate对三种状态的监控。hibernate很强大啊!
(前提是在Employee.hbm.xml中没有非空限制<many-to-one name="depart" column="depart_id" not-null="true" ></many-to-one>)

 

预告:尽请期待
 
一对多(Employee-Department)
一对一(Person-idcard)
多对对(teacher-student)
组件映射(User-Name)
集合映射(set,list,map,bag)
inverse和cascade(Employee-Department)

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值