关于多对一,一对多,一对一的解释见我之前写的博客mybatis(三)
这里介绍的是hibernate中多对一,一对多,一对一的应用。
Dept实体
public class Dept { private Integer deptno; private String deptname; }
Emp实体
public class Emp { private Integer empno; private String empname; //植入部门单个对象 private Dept dept;
}
一. 多对一(many-to-one)
多对一的配置是在多的一方植入少的一方的实体
Dept.hbm.xml 文件
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="cn.hibernate.mapping.entity"> <class name="Dept" table="Dept" > <id name="deptno" column="DEPTNO"> <generator class="native"/> </id> <property name="deptname" column="DEPTNAME"></property> </class> </hibernate-mapping>
这个配置文件没有任何特别之处。也没有关于多对一的配置
Emp.hbm.xml 文件
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="cn.hibernate.mapping.entity"> <class name="Emp" table="Emp" > <id name="empno" column="EMPNO"> <generator class="native"/> </id> <property name="empname" column="EMPNAME"></property> <many-to-one name="dept" class="Dept" column="deptno"></many-to-one> </class> </hibernate-mapping>
该文件中出了常规属性的配置外,将植入的少的一方的实体
在多对一中就使用<many-to-one name="dept" class="Dept" column="deptno"></many-to-one>节点
name:指的是在实体类中植入的实体的属性名
Class:指的是该name的类型
column:指的是在底层数据库中关联另一张表的的列(例:在该环境中就表示与dept表中的deptno关联的列,该列在emp表中)
单测:
1.查询一号员工对应的部门
@Test public void sel(){ Session session = HibernateUtil.getSession(); Emp emp = session.load(Emp.class, 1); System.out.println(emp.getEmpname()); System.out.println(emp.getDept().getDeptname()); HibernateUtil.closeSession(); }
结果:
2.保存员工到某个部门下
@Test public void add(){ Session session = HibernateUtil.getSession(); Dept dept=new Dept(); dept.setDeptno(1); Emp emp=new Emp(); emp.setEmpname("hehehe"); emp.setDept(dept); session.save(emp); HibernateUtil.closeSession(); }
二.一对多
在少的一方植入一个HashSet集合
如:
public class Dept { private Integer deptno; private String deptname; private Set<Emp> emps=new HashSet<Emp>(); }
在相应的配置文件中加入
<set name="emps"> <key column="deptno"></key> <one-to-many class="Emp"></one-to-many> </set>
相应的:name:为植入得到set集合的属性名
column:为该集合中的每一项与当前表的那一列有关系
class:集合中的值是什么类型
单测:
@Test public void sel(){ Session session = HibernateUtil.getSession(); String hql="from Dept"; Query query = session.createQuery(hql); List<Dept> list = query.list(); for (Dept dept:list){ System.out.println(dept.getDeptname()); for (Emp emp:dept.getEmps()){ System.out.println(emp.getEmpname()); } System.out.println("================"); } HibernateUtil.closeSession(); }
结果:
三. 一对一
与多对一非常相似,只是多的一方变为了一
这时你有两种方案来时实现该用法
1.假设每一个部门有且只有一个员工,来实现一对一只需要在 员工类和部门类中互相植入对方的属性即可,
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="cn.hibernate.mapping.entity"> <class name="Dept" table="Dept" > <id name="deptno" column="DEPTNO"> <generator class="native"/> </id> <property name="deptname" column="DEPTNAME"></property> <one-to-one name="emp" class="Emp"></one-to-one> </class> </hibernate-mapping>
Emp.hbm.xml中的<many-to-one name="dept" class="Dept" column="deptno" unique="true"></many-to-one>标签中设置"unique"="true"。即可
2.将<many-to-one name="dept" class="Dept" column="deptno" unique="true"></many-to-one>节点改为
<one-to-one name="demp" class="Demp"></one-to-one>
四.控制属性
Hibernate中控制属性主要有 cascade, inverse , order-by
1.cascade(级联)
Cascade取值:None,save-update,delete和all
none:当Session操纵当前对象时,忽略其他关联的对象。它是cascade属性的默认值.
Save-update:当通过Session的save()、update()及saveOrUpdate()方法来保存或更新当前对象时,级联保存所有关联的新建的瞬时状态的对象,并且级联更新所有关联的游离状态的对象。
Delete:当通过Session的delete()方法删除当前对象时,会级联删除所有关联的对象。当通过Session的delete()方法删除当前对象时,会级联删除所有关联的对象。
All:包含save-update,delete的行为。
注意点:级联也就是说当我们保存持久化对象A的时候自动帮我们保存持久化对象B。而取值就是他的策略,决定了在什么时候会使用级联
问题:cascade属性写在什么位置?
解析:一对一或者多对一的时候,直接写在标签上,其他的写在set标签上。
2.inverse
inverse属性指定了关联关系中的方向。
inverse设置为false,则为主动方,由主动方负责维护关联关系,默认是false 。
注意:inverse 决定是否把对对象中集合的改动反映到数据库中,所以inverse只对集合起作用,也就是只对one-to-many或many-to-many有效(因 为只有这两种关联关系包含集合,而one-to-one和many-to-one只含有关系对方的一个引用)。
Eg.测试代码如下:
tran = session.beginTransaction();
//准备一个Department对象
Department dept=new Department();
dept.setName("财务部");
//准备一个Employee对象
Employee emp=new Employee();
emp.setName("甄子丹");
//员工指定自己所属的部分
emp.setDept(dept);
dept.getEmployees().add(emp);
session.save(dept);
// 事务提交
tran.commit();
System.out.println("成功");
说明:如果我既给员工指定了自己所属的部门,又将员工添加到部门集合中。那么这个时候reverse不设置,生成以下sql
inverse设置为true,不负责维护关联关系
观察发现,其实第二条insert语句已经在员工表中指定了自己所属的部分,没有必要再向数据库发送一条update指令。
将inverse设置成true后,生成的语句如下图所示。
1.3 order-by
Hibernate如何对集合中的元素进行排序
解析:由于使用Hibernate后,生成SQL的重任交给了Hibernate,所以Hibernate给我们留了一条绿色通道,可以让我们很容易的对集合中的数据进行排序。那就是使用order-by,使用order-by用于在数据库中对集合进行排序。
Eg.核心测试代码
Set集合设置如下:
<set name="employees" cascade="save-update" inverse="true" order-by="id asc">
<key column="deptid"></key>
<one-to-many class="Employee"/>
</set>
注意:id是数据库表Employee中的列名,不是持久化类的属性名
List<Department> list = session.createQuery("from Department").list();
for (Department dept : list) {
for (Employee emp : dept.getEmployees()) {
System.out.println(emp.getId()+"\t"+emp.getName());
}
}
结果:
66 张三
67 李四
同一个部门下的员工编号按照升序排序