【SSH快速进阶】——Hibernate 多对一映射 和 一对多映射

简介: 上两篇文章说了一对一映射,这里说一下多对一 和 一对多的映射情况。

上两篇文章说了一对一映射,这里说一下多对一 和 一对多的映射情况。


47.png


 现实中有很多场景需要用到多对一或者一对多,比如上面这两个类图所展现出来的,一般情况下,一个部门会有多名员工,一名员工只在一个部门任职。




多对一关联映射


 在上面的场景中,对于Employee来说,它跟Department的关系就是多对一。



 PO对象


  Employee.java


public class Employee {
    public int id;
    public String name;
    public Department department;
    //getter、setter
}


   Department.java

public class Department {
    public int id;
    public String name;
    //getter、setter
}


  配置多对一关系时,设计po类时,除了写出最基本的属性(比如Employee的id、name),在对应“多”的那个类(比如Employee.java)中添加对应“一”那个类的引用(比如上面的department)。


  映射文件

   Employee.hbm.xml


<hibernate-mapping package="org.hibernate.test" >
    <class name="com.danny.hibernate.Employee" table="t_employee">
            <id name="id" type="int">
                <generator class="native"/>
            </id>
            <property name="name"/>
            <many-to-one name="department" column="departmentid"/>
    </class>
</hibernate-mapping>


   Department.hbm.xml

<hibernate-mapping package="org.hibernate.test" >
    <class name="com.danny.hibernate.Department" table="t_department">
            <id name="id">
                <generator class="native"/>
            </id>
            <property name="name"/>
    </class>
</hibernate-mapping>


  映射文件中的内容基本上跟它关联的类中的字段都是对应的。主键配置在<id></id>中,基本字段配置在<property/>中,对其他类的引用配置在<many-to-one/>中。


  运行代码执行的建表语句为:

alter table t_employee drop foreign key FKFDCF5A196E78D697
drop table if exists t_department
drop table if exists t_employee
create table t_department (id integer not null auto_increment, name varchar(255), primary key (id))
create table t_employee (id integer not null auto_increment, name varchar(255), departmentid integer, primary key (id))
alter table t_employee add index FKFDCF5A196E78D697 (departmentid), add constraint FKFDCF5A196E78D697 foreign key (departmentid) references t_department (id)


  从建表语句中可以看出来,t_employee表中的外键departmentid与t_department表中的主键相关联。

  生成的表结构如下:


48.png


  下面进行简单测试


  插入测试

session.beginTransaction();
Department department=new Department();
department.setName("信息部");
Employee employee1=new Employee();
employee1.setName("小胡");
employee1.setDepartment(department);
Employee employee2=new Employee();
employee2.setName("小玉");
employee2.setDepartment(department);
session.save(employee1);
session.save(employee2);
session.getTransaction().commit();


  一执行,发现报错了:org.hibernate.TransientObjectException,一看错误就知道,这是因为department还在Transient状态时,session是不能对其操作的。所以可以在事务提交之前先save一下department:


session.beginTransaction();
Department department=new Department();
department.setName("信息部");
Employee employee1=new Employee();
employee1.setName("小胡");
employee1.setDepartment(department);
Employee employee2=new Employee();
employee2.setName("小玉");
employee2.setDepartment(department);
session.save(department);           
session.save(employee1);
session.save(employee2);
session.getTransaction().commit();


  这样就可以成功插入了:

49.png


  还有一种更简单的方法,就是在映射文件Employee.hbm.xml的<many-to-one/>中配置cascade属性,值为"save-update"


   Employee.hbm.xml


<hibernate-mapping package="org.hibernate.test" >
    <class name="com.danny.hibernate.Employee" table="t_employee">
            <id name="id" type="int">
                <generator class="native"/>
            </id>
            <property name="name"/>
            <many-to-one name="department" column="departmentid" cascade="save-update"/>
    </class>
</hibernate-mapping>


 cascade表示两个对象之间的操作为联动关系,即对一个对象执行了操作之后,对其指定的级联对象也要进行相同的操作。Hibernate文档对cascade的解释为:

 "cascade(级联) (可选): 指明哪些操作会从父对象级联到关联的对象。它的值代表着Hibernate基本操作的名称, persist, merge, delete, save-update, evict, replicate, lock, refresh……"



 查询测试


session.beginTransaction();
Employee employee=(Employee)session.load(Employee.class, 1);
System.out.println("employee的name:"+employee.getName());
System.out.println("department的name:"+employee.getDepartment().getName());
session.getTransaction().commit();


  测试结果:

employee的name:小玉
department的name:信息部


一对多关联映射


 既然Employee对Department的关系是多对一,那么反之,Department对Employee就是一对多的关系。


 所以要在Department的PO类中增加一个Employee对象的集合。这个集合可以是set、list、map甚至array等容器,由于set中的对象不可重复,并且性能更高,所以一般用set。



 PO对象


  Department.java


public class Department {
    public int id;
    public String name;
    public Set<Employee> employees;
    //getter、setter
}


 

  Employee.java

public class Employee {
    public int id;
    public String name;
    //getter、setter
}


  映射文件

   Employee.hbm.xml


<hibernate-mapping package="org.hibernate.test" >
    <class name="com.danny.hibernate.Employee" table="t_employee">
            <id name="id" type="int">
                <generator class="native"/>
            </id>
            <property name="name"/>
    </class>
</hibernate-mapping>


   Department.hbm.xml


<hibernate-mapping package="org.hibernate.test" >
    <class name="com.danny.hibernate.Department" table="t_department">
            <id name="id">
                <generator class="native"/>
            </id>
            <property name="name"/>
            <set name=employees>
            <key column="departmentid"></key><!-- "多"的一方关联"一"的一方的外键 -->
            <one-to-many class="com.bjpowernode.hibernate.Employee"/><!-- 一个Department对象对应多个Employee对象 -->
            </set>
    </class>
</hibernate-mapping>


  映射文件Department.hbm.xml中添加了set标签,对应Department类中的集合employees,表示一个Department对象对应多个Employee对象。


  插入测试

session.beginTransaction();
Employee employee1=new Employee();
employee1.setName("小玉玉");
Employee employee2=new Employee();
employee2.setName("小洋洋");
Set<Employee> employees=new HashSet<Employee>();
employees.add(employee1);
employees.add(employee2);
Department department=new Department();
department.setName("信息部");
department.setEmployees(employees);
session.save(employee1);
session.save(employee2);
session.save(department);
session.getTransaction().commit();


  插入结果:

50.png


  查询测试


session.beginTransaction();
Department department=(Department)session.load(Department.class,1);
System.out.println("department的name:"+department.getName());
System.out.println("department的employee有:");
for(Employee employee:department.getEmployees()){
    System.out.print(" "+employee.getName());
}
session.getTransaction().commit();


  控制台输出内容为:

Hibernate: select department0_.id as id0_0_, department0_.name as name0_0_ from t_department department0_ where department0_.id=?
department的name:信息部
department的employee有:Hibernate: select employees0_.departmentid as departme3_1_, employees0_.id as id1_, employees0_.id as id1_0_, employees0_.name as name1_0_ from t_employee employees0_ where employees0_.departmentid=?
 小洋洋 小玉玉


  由此可见,一对多的配置中,默认为延迟加载,相当于lazy=”true”。

  给映射文件中<set>标签的属性lazy设置为false时,不会延迟加载,即查询Department的时候,会把属于该Department的Employee全部查询出来。控制台输出内容为:

Hibernate: select department0_.id as id0_0_, department0_.name as name0_0_ from t_department department0_ where department0_.id=?
Hibernate: select employees0_.departmentid as departme3_1_, employees0_.id as id1_, employees0_.id as id1_0_, employees0_.name as name1_0_ from t_employee employees0_ where employees0_.departmentid=?
department的name:信息部
department的employee有: 
小洋洋 小玉玉


比较


 相同点:映射原理基本一致,建表时,都是在“多”的一端添加外键指向“一”的一端。


 区别:维护的关系不同

 多对一维护的关系:多指向一的关系,加载“多”的时候可以把“一”也加载出来;

 一对多维护的关系:一指向多的关系,加载“一”的时候可以把“多”也加载出来;


相关文章
|
7月前
|
网络安全
ssh(Spring+Spring mvc+hibernate)——DeptDaoImpl.java
ssh(Spring+Spring mvc+hibernate)——DeptDaoImpl.java
|
7月前
|
网络安全
ssh(Spring+Spring mvc+hibernate)——BaseDaoImpl.java
ssh(Spring+Spring mvc+hibernate)——BaseDaoImpl.java
|
3月前
|
Java 数据库连接 API
解锁高效开发秘籍:深入探究 Hibernate 如何优雅处理一对多与多对多关系,让数据映射再无烦恼!
【9月更文挑战第3天】Hibernate 是 Java 领域中最流行的 ORM 框架之一,广泛用于处理实体对象与数据库表之间的映射。尤其在处理复杂关系如一对多和多对多时,Hibernate 提供了丰富的 API 和配置选项。本文通过具体代码示例,展示如何使用 `@OneToMany`、`@JoinColumn`、`@ManyToMany` 和 `@JoinTable` 等注解优雅地实现这些关系,帮助开发者保持代码简洁的同时确保数据一致性。
65 4
|
4月前
|
XML JSON Java
使用IDEA+Maven搭建整合一个Struts2+Spring4+Hibernate4项目,混合使用传统Xml与@注解,返回JSP视图或JSON数据,快来给你的SSH老项目翻新一下吧
本文介绍了如何使用IntelliJ IDEA和Maven搭建一个整合了Struts2、Spring4、Hibernate4的J2EE项目,并配置了项目目录结构、web.xml、welcome.jsp以及多个JSP页面,用于刷新和学习传统的SSH框架。
117 0
使用IDEA+Maven搭建整合一个Struts2+Spring4+Hibernate4项目,混合使用传统Xml与@注解,返回JSP视图或JSON数据,快来给你的SSH老项目翻新一下吧
|
4月前
|
Java 数据库连接 数据库
AI 时代风起云涌,Hibernate 实体映射引领数据库高效之路,最佳实践与陷阱全解析!
【8月更文挑战第31天】Hibernate 是一款强大的 Java 持久化框架,可将 Java 对象映射到关系数据库表中。本文通过代码示例详细介绍了 Hibernate 实体映射的最佳实践,包括合理使用关联映射(如 `@OneToMany` 和 `@ManyToOne`)以及正确处理继承关系(如单表继承)。此外,还探讨了常见陷阱,例如循环依赖可能导致的无限递归问题,并提供了使用 `@JsonIgnore` 等注解来避免此类问题的方法。通过遵循这些最佳实践,可以显著提升开发效率和数据库操作性能。
91 0
|
4月前
|
数据库 开发者 Java
Hibernate映射注解的魔力:实体类配置的革命,让你的代码量瞬间蒸发!
【8月更文挑战第31天】Hibernate 是一款出色的对象关系映射框架,简化了 Java 应用与数据库的交互。其映射注解让实体类配置变得直观简洁。本文深入剖析核心概念与使用技巧,通过示例展示如何简化配置。
55 0
|
7月前
|
网络安全
ssh(Spring+Spring mvc+hibernate)——Dept.java
ssh(Spring+Spring mvc+hibernate)——Dept.java
|
7月前
|
网络安全
ssh(Spring+Spring mvc+hibernate)——showDept.jsp
ssh(Spring+Spring mvc+hibernate)——showDept.jsp
|
7月前
|
网络安全
ssh(Spring+Spring mvc+hibernate)——applicationContext.xml
ssh(Spring+Spring mvc+hibernate)——applicationContext.xml
|
7月前
|
网络安全
ssh(Spring+Spring mvc+hibernate)——EmpController
ssh(Spring+Spring mvc+hibernate)——EmpController