一对多(one-to-many)双向关联实例(Department- Employee)
这里的一对多双向关联是在域模型(实体对象模型)上的概念,在关系数据库中,只存在外键参照关系,而且总是由"many"方参照"one"方,因为这样才能消除冗余数据,因上关系数据库实际上只支持多对一或一对一的单向关联.在实体(类与类之间)各种各样的关系中,数多对一的的单向关联关系与数据库中的外键参照关系最匹配了.
在我的前一篇文章多对一的基础上进行修改。
1.修改Department实体类:
- package com.reiyen.hibernate.domain
- public class Department {
- private int id;
- private String name;
- private Set<Employee> emps;
- //setter和getter方法
- }
package com.reiyen.hibernate.domain public class Department { private int id; private String name; private Set<Employee> emps; //setter和getter方法 }
2.修改Department.hbm.xml文件:
- <?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping package="com.reiyen.hibernate.domain">
- <class name="Department" >
- <id name="id" >
- <generator class="native" />
- </id>
- <property name="name" />
- <set name="emps">
- <key column="depart_id" />
- <one-to-many class="Employee"/>
- </set>
- </class>
- </hibernate-mapping>
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.reiyen.hibernate.domain"> <class name="Department" > <id name="id" > <generator class="native" /> </id> <property name="name" /> <set name="emps"> <key column="depart_id" /> <one-to-many class="Employee"/> </set> </class> </hibernate-mapping>
<set>元素的属性name:设定待映射的持久化类的属性名,这里为Depatment类的emps属性.
<set>元素的两个子元素:
<key>:设定与所关联的持久化类对应的表的外键,此处为Employee表的depart_id字段.
<one-to-many>:设定所关联的持久化类,此处为Employee.
Hibernate根椐以上配置信息获得如下信息:
<set>元素表明Department类的emps属性为java.util.Set集合类型.
<class>子元素表明emps集合中存放的是一组Employee对象
<key>子元素表明employee表是通过外键depart_id参照department表的.
3. 其余的保持原样,测试类如下:
- public class Many2One {
- /**
- * @param args
- */
- public static void main(String[] args) {
- Department depart = add();
- Department department = queryDepart(depart.getId());
- //department.getEmps();3
- // System.out.println("emp size:" + department.getEmps().size());4
- }
- static Department queryDepart(int departId) {
- Session s = null;
- Transaction tx = null;
- try {
- s = HibernateUtil.getSession();
- tx = s.beginTransaction();
- Department depart = (Department) s.get(Department.class, departId);
- System.out.println("emp size:" + depart.getEmps().size());//1
- // System.out.println("emps class:" + depart.getEmps().getClass()); //2
- // Hibernate.initialize(depart.getEmps());
- tx.commit();
- return depart;
- } finally {
- if (s != null)
- s.close();
- }
- }
- static Department add() {
- Session s = null;
- Transaction tx = null;
- try {
- Department depart = new Department();
- depart.setName("department name");
- Employee employee1 = new Employee();
- employee1.setDepartment(depart); // 对象模型:建立两个对象的关联
- employee1.setName("employee1 name2");
- Employee employee2 = new Employee();
- employee2.setDepartment(depart); // 对象模型:建立两个对象的关联
- employee2.setName("employee2 name2");
- // Set<Employee> set = new HashSet<Employee>();
- // set.add(employee1);
- // set.add(employee2);
- // depart.setEmps(set);
- s = HibernateUtil.getSession();
- tx = s.beginTransaction();
- s.save(depart);
- s.save(employee1);
- s.save(employee2);
- tx.commit();
- return depart;
- } finally {
- if (s != null)
- s.close();
- }
- }
- }
public class Many2One { /** * @param args */ public static void main(String[] args) { Department depart = add(); Department department = queryDepart(depart.getId()); //department.getEmps();3 // System.out.println("emp size:" + department.getEmps().size());4 } static Department queryDepart(int departId) { Session s = null; Transaction tx = null; try { s = HibernateUtil.getSession(); tx = s.beginTransaction(); Department depart = (Department) s.get(Department.class, departId); System.out.println("emp size:" + depart.getEmps().size());//1 // System.out.println("emps class:" + depart.getEmps().getClass()); //2 // Hibernate.initialize(depart.getEmps()); tx.commit(); return depart; } finally { if (s != null) s.close(); } } static Department add() { Session s = null; Transaction tx = null; try { Department depart = new Department(); depart.setName("department name"); Employee employee1 = new Employee(); employee1.setDepartment(depart); // 对象模型:建立两个对象的关联 employee1.setName("employee1 name2"); Employee employee2 = new Employee(); employee2.setDepartment(depart); // 对象模型:建立两个对象的关联 employee2.setName("employee2 name2"); // Set<Employee> set = new HashSet<Employee>(); // set.add(employee1); // set.add(employee2); // depart.setEmps(set); s = HibernateUtil.getSession(); tx = s.beginTransaction(); s.save(depart); s.save(employee1); s.save(employee2); tx.commit(); return depart; } finally { if (s != null) s.close(); } } }
控制台打印信息如下:
Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: select department0_.id as id1_0_, department0_.name as name1_0_ from Department department0_ where department0_.id=?
Hibernate: select emps0_.depart_id as depart3_1_, emps0_.id as id1_, emps0_.id as id2_0_, emps0_.name as name2_0_, emps0_.depart_id as depart3_2_0_ from Employee emps0_ where emps0_.depart_id=?
emp size:2
数据库中记录如下所示:
mysql> select * from employee;
+----+-----------------+-----------+
| id | name | depart_id |
+----+-----------------+-----------+
| 1 | employee1 name2 | 1 |
| 2 | employee2 name2 | 1 |
+----+-----------------+-----------+
2 rows in set (0.00 sec)
mysql> select * from department;
+----+-----------------+
| id | name |
+----+-----------------+
| 1 | department name |
+----+-----------------+
1 row in set (0.00 sec)
虽然对象模型修改了,但数据库关系模型并没有改变。
如果把测试程序中注释部分去掉,同时将注释为“建立对象模型”这两句程序注释掉,虽然也能正确运行,但控制台会多打印出两条更新语句,说明数据库多执行了两次更新操作,效率上有影响,如下所示:
Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: update Employee set depart_id=? where id=?
Hibernate: update Employee set depart_id=? where id=?
Hibernate: select department0_.id as id1_0_, department0_.name as name1_0_ from Department department0_ where department0_.id=?
Hibernate: select emps0_.depart_id as depart3_1_, emps0_.id as id1_, emps0_.id as id2_0_, emps0_.name as name2_0_, emps0_.depart_id as depart3_2_0_ from Employee emps0_ where emps0_.depart_id=?
emp size:2
4.懒加载分析:
(1)如果将程序中标记为1的程序注释掉,控制台打印信息如下:
Hibernate: select department0_.id as id0_0_, department0_.name as name0_0_ from Department department0_ where department0_.id=?
此时只是将Department对象查询出来了,而对应的Employee并没有进行查询。
(2)如果将程序中标记为1的程序注释掉,同时将标记为2的前面的注释去掉,运行程序,控制台打印信息如下:
Hibernate: select department0_.id as id0_0_, department0_.name as name0_0_ from Department department0_ where department0_.id=?
emps class:class org.hibernate.collection.PersistentSet
此时可以看到其实Hibernate将hashset替换成了它自己写的PersistentSet,所以才能实现懒加载功能。同时可以发现当调用department.getEmps();hibernate只是获取了集合代理对象的引用,它并没有去查询数据库来填充集合对象。你还可以进一步测试来验证这个问题。如果你 将程序中标记为1的程序注释掉,同时去掉标记为3的语句前面的注释,你会发现程序能正常运行,但如果去掉标记为4的语句前面的注释,运行程序,则会抛出如下异常:
org.hibernate.LazyInitializationException : failed to lazily initialize a collection of role: com.reiyen.hibernate.domain.Department.emps, no session or session was closed
(3)当进行department对象查询时,从department的表结构中也不能判断这个Department对象是否有对应的Employee,那为什么它不像一对一查询时,也一次性把相关联的对象查询出来呢??这是因为如果将关联的对象查询出来的话,因为数据较多,它会严重影响效率,而不像一对一时,反正从对象只有一个,一次性查询出来影响也不是太大,所以hibernate就假定你有相对应的Employee,直接创建了一个集合代理对象的返回给你(把对象引用先给你),等你需要数据的时候再去查询数据库,以提高效率!
相关推荐
一、一对一(one-to-one)与一对多(one-to-many)关系 1. 一对一关系: 在现实世界中,如一个人只有一个身份证,这就是典型的"一对一"关系。在Hibernate中,可以通过@OneToOne注解实现。这种关系通常需要使用外键...
在配置双向一对多关联时,我们通常在"多"一端(这里是`Student`)的集合属性上使用`<many-to-one>`标签,将`Classes`对象映射到数据库中的外键。同时,在"一"端(`Classes`)使用`<set>`标签,表示班级可以包含多个...
本话题主要探讨两种基本的关系映射类型:many-to-one(多对一)和one-to-many(一对多)。这两种关系映射是数据库中常见的关联类型,理解和掌握它们对于开发高质量的Java应用至关重要。 1. many-to-one关系 many-to...
在本文中,我们将详细介绍Hibernate一对一唯一外键关联映射的概念、配置方法和实践应用。 一对一唯一外键关联映射的概念 在Hibernate中,一对一唯一外键关联映射是指两个实体之间的关联关系,其中一个实体作为外键...
本文主要关注Hibernate中的一个核心概念——一对一(One-to-One)、一对多(One-to-Many)和多对一(Many-to-One)关联映射,特别是关于“一到多”单向和双向关联映射的配置心得。 首先,让我们了解“一到多”关联...
在Hibernate中,`one-to-many`关系是常见的实体间关系之一,表示一个实体可以与多个其他实体相关联。本文将深入探讨`Hibernate one-to-many`注解的使用和实现细节。 ### 一、`@OneToMany`注解概述 `@OneToMany`...
标题"hibernate一对多,多对一,一对多双向关联"指涉的是Hibernate框架中常见的关系映射概念。在数据库设计中,实体间的关系通常包括一对一(One-to-One)、一对多(One-to-Many)和多对一(Many-to-One)关系,而在...
在Java的持久化框架Hibernate中,一对多(Many-to-One)和多对一(One-to-Many)的关系映射是数据库关系模型中的常见关联类型。本文将深入探讨这两种关联方式在使用Hibernate时的配置,包括基于注解(Annotation)和...
总结起来,Hibernate的双向一对多关联映射(XML)涉及的主要知识点包括:实体类的关联、`<set>`和`<one-to-many>`标签的使用、`<many-to-one>`标签的使用、以及如何在Java代码中维护这种关联。理解并熟练运用这些...
在实体类之间,Hibernate支持多种关联关系,包括一对一(One-to-One)、一对多(One-to-Many)和多对多(Many-to-Many)。本资源主要探讨的是“hibernate一对一关联关系”。 一对一关联关系在现实世界中很常见,...
关联映射主要包括四种类型:一对一(One-to-One)、一对多(One-to-Many)、多对一(Many-to-One)和多对多(Many-to-Many)。下面我们将逐一探讨这些关联映射的配置方法。 1. **一对一关联映射** - **主键关联**...
在探讨“Hibernate一对多双向”这一主题时,我们首先需要理解Hibernate框架以及它在Java开发中的重要性。Hibernate是一个开放源代码的对象关系映射(ORM)框架,它为Java应用程序提供了一种将对象模型与数据库模型相...
在Hibernate的一对多关联中,双向关联意味着双方都可以通过导航属性访问对方。例如,用户类(User)可以有一个订单集合(Orders),而订单类(Order)同样有一个用户属性(User)。这样设计的好处在于,我们可以在任一侧轻松...
Many-to-One关系是现实世界中常见的关联类型,一个实体可能对应另一个实体的多个实例,例如,一个员工可以属于一个部门,但一个部门可能有多个员工。在Hibernate中,Many-to-One关系通过配置实现,主要涉及以下几点...
9. Hibernate 一对一外键双向关联、主键双向关联、连接表双向关联、一对多外键双向关联、一对多连接表双向关联、多对多双向关联: 这些关联方式与单向关联类似,区别在于两个实体类都知道彼此的关联。在双向关联中...
在这个“hibernate实例(一对多,多对一)”的主题中,我们将深入探讨两种重要的关联关系:一对一(One-to-One)和一对多(One-to-Many)。 **一对一关联(One-to-One)** 在一对一关联中,一个实体与另一个实体之间...
3. **一对多关联(One-to-Many Association)**:使用`@OneToMany`注解在父类(拥有多个子项的一方)中声明,表示一个实体可以与多个其他实体相关联。可以通过`mappedBy`属性指定关联的另一端。 4. **多对一关联...
- `many-to-one`关联可以用来表达多种类型的关系,包括一对一、一对多和多对一。 - 双向`many-to-one`关联的例子,比如麻将桌上的玩家位置与玩家之间的关系。 #### 三、`one-to-one`关联管理 `one-to-one`关联...
标题中的“hibernate_1700_one2many_many2one_bi_crud(5)”指的是一项关于Hibernate框架的教程,重点在于介绍一对多(One-to-Many)和多对一(Many-to-One)双向关联关系的创建、读取、更新和删除(CRUD)操作。...