多对一实例(Employee-Department)
1. E-R图:
2. 实体类:
Department类:
package com.reiyen.hibernate.domain
public class Department {
private int id;
private String name;
//setter和getter方法....
}
Employee类:
package com.reiyen.hibernate.domain
public class Employee {
private int id;
private String name;
private Department department;
//setter和getter方法
}
3. 实体映射文件:
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" />
</class>
</hibernate-mapping>
Employee.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="Employee">
<id name="id">
<generator class="native" />
</id>
<property name="name" />
<!-- name="department" 这个名称必须与Employee中的属性名一致. -->
<many-to-one name="department" column="depart_id" class="Department" />
</class>
</hibernate-mapping>
<many-to-one name=”department” column=”depart_id” />这种缺省情况,
hibernate会默认去department对象中查找主键值,因为hibernate默认的是外键对应另一个表中的主键的,
如果想对应department中的其它属性,如”name”,则可以使用<many-to-one name=”department” column=”depart_id” property-ref=”name”/>也可以使用<many-to-one name=”department” />,这与 <many-to-one name=”depart” column=”depart_id” />的唯一区别就是它的column名也为department了,而不是depart_id.
<many-to-one >元素建立了department属性和employee表的外键depart_id之间的映射.
name: 设定待映射的持久化类的属性名,此外为employee类的department属性.
column: 设定和持久化类的属性对应的表的外键,此外为employee表的外键depart_id.
class(可选):设定持久化类的属性的类型,此处设定department的类型是Department类.
not-null(可选):如果为true,表示department属性不能为null,该属性的默认值为false.当为true时,生成的employee表中depart_id外键会设置not-null约束,所以当Hibernate保存Employee对象时,会先检查它的department属性是否为null,如果为null,则会抛出异常.
3. 将两个实体映射文件在hibernate.cfg.xml配置文件中注册:(hibernate.cfg.xml在我一篇文章:第一个Hibernate实例
中有)
<mapping resource="com/reiyen/hibernate/domain/Department.hbm.xml" />
<mapping resource="com/reiyen/hibernate/domain/Employee.hbm.xml" />
4. 测试:
public class Many2One {
public static void main(String[] args) {
Department depart = add();
System.out.println("depart name: " + depart.getName());
}
static Department add() {
Session s = null;
Transaction tx = null;
try {
Department depart = new Department();
depart.setName("department name");
Employee employee = new Employee();
employee.setDepartment(depart); // 对象模型:建立两个对象的关联
employee.setName("employee name");
s = HibernateUtil.getSession();
tx = s.beginTransaction();
s.save(depart);
s.save(employee);
tx.commit();
return depart;
} finally {
if (s != null)
s.close();
}
}
}
运行后,控制台打印信息如下:
Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
depart name: department name
查看Employee数据库表的创建语句如下:(注意红色部分)
DROP TABLE IF EXISTS `test`.`employee`;
CREATE TABLE `test`.`employee` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`depart_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FK4AFD4ACEA3E9AC0F` (`depart_id`),
CONSTRAINT `FK4AFD4ACEA3E9AC0F` FOREIGN KEY (`depart_id`) REFERENCES `department` (`id`))
ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
表中插入记录如下:
mysql> select * from employee;
+----+---------------+-----------+
| id | name | depart_id |
+----+---------------+-----------+
| 1 | employee name | 1 |
+----+---------------+-----------+
1 row in set (0.00 sec)
mysql> select * from department;
+----+-----------------+
| id | name |
+----+-----------------+
| 1 | department name |
+----+-----------------+
1 row in set (0.00 sec)
调换测试类两句程序的顺序,如下所示:
s.save(employee);
s.save(depart);
则控制台的信息如下所示:(多了一条更新语句)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Department (name) values (?)
Hibernate: update Employee set name=?, depart_id=? where id=?
depart name: department name
employee.setDepartment(depart); // 对象模型:建立两个对象的关联
这句话很重要,如果没有这句话,则Department和Employee之间就没有任何关系了。
如果你在Employee.hbm.xml中配置了
<many-to-one name="department" column="depart_id" not-null="true"/>
则必须先保存department再保存employee,否则会抛出:
org.hibernate.PropertyValueException: not-null property references a null or transient value
异常!
查询测试:
public class Many2One {
public static void main(String[] args) {
Department depart = add();
Employee employee = query(1);
// System.out.println("depart name:" + employee.getDepartment().getName()); // 2
}
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);
System.out.println("depart name:" + emp.getDepartment().getName()); // 1
// System.out.println("depart class:" + emp.getDepartment().getClass()); // 4
//System.out.println("depart id:" + emp.getDepartment().getId()); //5
// Hibernate.initialize(emp.getDepartment()); // 3
tx.commit();
return emp;
} finally {
if (s != null)
s.close();
}
}
}
测试程序运行后,控制台打印出的sql如下:
Hibernate: select employee0_.id as id2_0_, employee0_.name as name2_0_, employee0_.depart_id as depart3_2_0_ from Employee employee0_ where employee0_.id=?
Hibernate: select department0_.id as id1_0_, department0_.name as name1_0_ from Department department0_ where department0_.id=?
depart name:department name
当相关联的session没有关闭时,访问这些懒加载对象(代理对象)的属性(getId和getClass除外)时,hibernate会初始化这些代理,所以将Employee对象和Department对象都查询出来了。相当于在数据库中执行两次查询:
首先执行select * from employee where employee.id = ?
然后再执行select * from department where department.id = ?
如果将测试程序中标记为2的语句前的注释去掉,同时把标记为1的语句注释掉,再运行刚会出现如下所示的异常:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
解决办法是把标记为3的语句前的注释去掉,即初始化懒加载的代理对象。(可以给query方法再传递一个参数,如boolean isInit,如果是true的话就初始化代理对象,即调用
Hibernate.initialize(emp.getDepartment())
否则,就不初始化代理对象)。
5.懒加载说明:
many-to-one(元素)懒加载:1).lazy!=false 2).fetch=select
能够懒加载的对象都是被改写过的代理对象,当相关联的session没有关闭时,访问这些懒加载对象(代理对象)的属性(getId和getClass除外)时,hibernate会初始化这些代理,或用Hibernate.initialize(proxy)来初始化代理对象;
当相关联的session关闭后,再访问懒加载的对象将会出现异常。
(1)把标记为1的语句注释掉,同时去掉标记为4的语句前面的注释,进行测试,控制台打印信息如下所示:
Hibernate: select employee0_.id as id1_0_, employee0_.name as name1_0_, employee0_.depart_id as depart3_1_0_ from Employee employee0_ where employee0_.id=?
depart class:class com.itcast.hibernate.domain.Department$$EnhancerByCGLIB$$b412e7fa
说明实现了懒加载,它只查询出Employee对象,而没有去查询相应的Department对象;同时可以看出,返回的是改写过的代理对象,而不是实体类Department.
(2)把标记为1的语句注释掉,同时去掉标记为5的语句前面的注释,进行测试,控制台打印信息如下所示:
Hibernate: select employee0_.id as id1_0_, employee0_.name as name1_0_, employee0_.depart_id as depart3_1_0_ from Employee employee0_ where employee0_.id=?
depart id:1
当相关联的session没有关闭时,访问这些懒加载对象(代理对象)getId和getClass属性,hibernate不会初始化这些代理。
分享到:
相关推荐
在上面的配置中, `<many-to-one>` 标签指定了Person实体与IdCard实体之间的一对一唯一外键关联关系,其中unique="true"指定了多的一端的多重性为一。 Hibernate 一对一唯一外键关联映射的应用 在实际应用中,一对...
3. **映射文件**:如果使用传统的Hibernate XML映射文件,需要在`.hbm.xml`文件中配置多对一关联,设置`<many-to-one>`标签。如果是注解方式,直接在Java类中使用上述提到的注解。 4. **数据访问对象(DAO)**:...
本文主要关注Hibernate中的一个核心概念——一对一(One-to-One)、一对多(One-to-Many)和多对一(Many-to-One)关联映射,特别是关于“一到多”单向和双向关联映射的配置心得。 首先,让我们了解“一到多”关联...
1. **配置XML映射文件**:在实体类的XML映射文件中,使用`<many-to-one>`标签定义多对一关联。例如,如果有一个`Employee`类对应`Department`类,可以在`Employee.hbm.xml`中写入以下代码: ```xml <many-to-one ...
6. Hibernate 多对一外键单向关联: 在多对一关联中,多个实体(如 Order)可以关联到一个实体(如 Customer)。在 Order 实体类中,会有 `many-to-one` 元素指向 Customer。 7. Hibernate 多对一连接表单向关联:...
在实体类之间,Hibernate支持多种关联关系,包括一对一(One-to-One)、一对多(One-to-Many)和多对多(Many-to-Many)。本资源主要探讨的是“hibernate一对一关联关系”。 一对一关联关系在现实世界中很常见,...
关联映射主要包括四种类型:一对一(One-to-One)、一对多(One-to-Many)、多对一(Many-to-One)和多对多(Many-to-Many)。下面我们将逐一探讨这些关联映射的配置方法。 1. **一对一关联映射** - **主键关联**...
在Java持久化框架Hibernate中,一对多外键单向关联是一种常见的关系映射方式,它描述了一对多的关系,其中一个实体(例如Person)可以与多个其他实体(例如Address)相关联,而关联的方向只从多方(Address)指向...
压缩包中的`s2sh_relation07_many2one_uni`可能是示例项目的名称,暗示这是一个基于Spring、Struts2和Hibernate(S2SH)的项目,其中包含了多对一单向关联的实例代码。你可以下载并运行这个项目,以便更直观地理解...
1. **在父类的映射文件中**,使用`<one-to-many>`元素声明一对多关联,并通过`class`属性指定子类的全限定类名。 ```xml <hibernate-mapping> <!-- 其他映射 --> ...
在本主题"Hibernate单向一对多关联映射(XML版)"中,我们将深入探讨如何使用XML配置来实现数据库中一个实体类对应多个实体类的关联关系。 在Hibernate中,一对多关联是一种常见的关系映射类型,它反映了数据库中的...
接下来是“多对一”(Many-to-One)映射,与一对多相反,一个子实体可以关联到多个父实体。例如,多个订单可以属于同一个客户。`hibernate_many2one`的案例可能展示了如何在子类中使用`@ManyToOne`注解来指定与父类...
- `many-to-one`关联可以用来表达多种类型的关系,包括一对一、一对多和多对一。 - 双向`many-to-one`关联的例子,比如麻将桌上的玩家位置与玩家之间的关系。 #### 三、`one-to-one`关联管理 `one-to-one`关联...
在`Department`类中,我们可以有一个`List<Employee>`属性,但`Employee`类不需要知道`Department`类的存在,这就是所谓的单向关联。 配置单向一对多关联,通常有以下几步: 1. **配置主类**:在主类(这里是`...
【标题】"hibernate-one-to-many-uni" 指的是在Hibernate框架下实现的一对多单向关联关系。Hibernate是Java开发中常用的持久化框架,它简化了数据库操作,使得开发者可以更加专注于业务逻辑而不是数据库交互。在这个...
单向关联分为单向一对一关联和单向一对多关联。这里我们先讨论单向一对多关联,它是最常见的关联类型之一,一个实体可以拥有多个其他实体实例。例如,一个部门可以有多个员工,但员工并不知道属于哪个部门,这就是...
本篇主要探讨的是如何在Hibernate中实现一对多的单向关联映射。 一、概念理解 一对多关联意味着一个实体(如部门)可以有多个关联实体(如员工),而反过来,每个员工只属于一个部门。单向关联则表示只有部门知道其...
2. **一对多关联**(One-to-Many / Many-to-One) - 外键单向关联 - 连接表单向关联 - 外键双向关联 - 连接表双向关联 3. **多对多关联**(Many-to-Many) - 单向关联 - 双向关联 每种关联类型都有其特定的...
在多对一外键单向关联中,多个实体(子实体)与一个实体(父实体)相关联,这种关联通过在子实体中添加一个指向父实体的外键来实现。 **表结构示例**: - **Department表**: - `departmentid`: 主键 - `...