`

hibernate 多对一(Many-to-one)单向关联

 
阅读更多

多对一实例(Employee-Department)

1. E-R图:

2. 实体类:

Department类:

Java代码 复制代码 收藏代码
  1. package com.reiyen.hibernate.domain   
  2.     public class Department {   
  3.   
  4.         private int id;   
  5.         private String name;   
  6.           //setter和getter方法....   
  7.     }  
package com.reiyen.hibernate.domain
	public class Department {

		private int id;
		private String name;
	      //setter和getter方法....
	}

 

 Employee类:

Java代码 复制代码 收藏代码
  1.       package com.reiyen.hibernate.domain   
  2. public class Employee {   
  3.   
  4.     private int id;   
  5.     private String name;   
  6.     private Department department;   
  7.     //setter和getter方法   
  8. }  
       package com.reiyen.hibernate.domain
	public class Employee {

		private int id;
		private String name;
		private Department department;
		//setter和getter方法
	}

 

  3. 实体映射文件:

Department.hbm.xml如下:

Xml代码 复制代码 收藏代码
  1. <?xml version="1.0"?>  
  2.     <!DOCTYPE hibernate-mapping PUBLIC    
  3.         "-//Hibernate/Hibernate Mapping DTD 3.0//EN"   
  4.         "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5.     <hibernate-mapping package="com.reiyen.hibernate.domain">  
  6.         <class name="Department" >  
  7.             <id name="id" >  
  8.                 <generator class="native" />  
  9.             </id>  
  10.             <property name="name" />  
  11.         </class>  
  12.     </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" />
		</class>
	</hibernate-mapping>

 

 Employee.hbm.xml如下:

Xml代码 复制代码 收藏代码
  1. <?xml version="1.0"?>  
  2.     <!DOCTYPE hibernate-mapping PUBLIC    
  3.         "-//Hibernate/Hibernate Mapping DTD 3.0//EN"   
  4.         "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5.     <hibernate-mapping package="com.reiyen.hibernate.domain">  
  6.         <class name="Employee">  
  7.             <id name="id">  
  8.                 <generator class="native" />  
  9.             </id>  
  10.             <property name="name" />  
  11.             <!-- name="department" 这个名称必须与Employee中的属性名一致. -->  
  12.             <many-to-one name="department" column="depart_id" class="Department" />  
  13.         </class>  
  14.     </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="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实例 中有)

Xml代码 复制代码 收藏代码
  1. <mapping resource="com/reiyen/hibernate/domain/Department.hbm.xml" />  
  2. <mapping resource="com/reiyen/hibernate/domain/Employee.hbm.xml" />  
<mapping resource="com/reiyen/hibernate/domain/Department.hbm.xml" />
<mapping resource="com/reiyen/hibernate/domain/Employee.hbm.xml" />

 4. 测试:

Java代码 复制代码 收藏代码
  1. public class Many2One {   
  2. public static void main(String[] args) {   
  3.         Department depart = add();   
  4.         System.out.println("depart name: " + depart.getName());   
  5.     }   
  6. static Department add() {   
  7.         Session s = null;   
  8.         Transaction tx = null;   
  9.         try {   
  10.             Department depart = new Department();   
  11.             depart.setName("department name");   
  12.             Employee employee = new Employee();   
  13.                employee.setDepartment(depart); // 对象模型:建立两个对象的关联   
  14.                        employee.setName("employee name");   
  15.             s = HibernateUtil.getSession();   
  16.             tx = s.beginTransaction();   
  17.             s.save(depart);   
  18.                     s.save(employee);   
  19.             tx.commit();   
  20.             return depart;   
  21.         } finally {   
  22.             if (s != null)   
  23.                 s.close();   
  24.         }   
  25.     }   
  26. }  
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;

 表中插入记录如下:

Sql代码 复制代码 收藏代码
  1. mysql> select * from employee;   
  2. +----+---------------+-----------+   
  3. | id | name          | depart_id |   
  4. +----+---------------+-----------+   
  5. |  1 | employee name |         1 |   
  6. +----+---------------+-----------+   
  7. 1 row in set (0.00 sec)   
  8.   
  9. mysql> select * from department;   
  10. +----+-----------------+   
  11. | id | name            |   
  12. +----+-----------------+   
  13. |  1 | department name |   
  14. +----+-----------------+   
  15. 1 row in set (0.00 sec)  
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)

 调换测试类两句程序的顺序,如下所示:

 

Java代码 复制代码 收藏代码
  1. s.save(employee);   
  2. s.save(depart);  
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

Java代码 复制代码 收藏代码
  1. employee.setDepartment(depart); // 对象模型:建立两个对象的关联  
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 异常!

查询测试:

Java代码 复制代码 收藏代码
  1. public class Many2One {   
  2.     public static void main(String[] args) {   
  3.         Department depart = add();   
  4.         Employee employee = query(1);   
  5.         // System.out.println("depart name:" + employee.getDepartment().getName()); // 2   
  6.     }   
  7.   
  8.     static Employee query(int empId) {   
  9.         Session s = null;   
  10.         Transaction tx = null;   
  11.         try {   
  12.             s = HibernateUtil.getSession();   
  13.             tx = s.beginTransaction();   
  14.             Employee emp = (Employee) s.get(Employee.class, empId);   
  15.             System.out.println("depart name:" + emp.getDepartment().getName()); // 1   
  16.               // System.out.println("depart class:" + emp.getDepartment().getClass()); // 4    
  17.              //System.out.println("depart id:" + emp.getDepartment().getId());  //5        
  18.             // Hibernate.initialize(emp.getDepartment()); // 3   
  19.             tx.commit();   
  20.             return emp;   
  21.         } finally {   
  22.             if (s != null)   
  23.                 s.close();   
  24.         }   
  25.     }   
  26. }  
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的话就初始化代理对象,即调用

Java代码 复制代码 收藏代码
  1. Hibernate.initialize(emp.getDepartment())  
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不会初始化这些代理。

分享到:
评论

相关推荐

    Hibernate学习笔记

    020 &lt;one-to-one&gt;、&lt;many-to-one&gt;单端关联上的 lazy(懒加载)属性 021 继承关联映射 022 component(组件)关联映射 023 复合主键 关联映射 024 其它 关联映射 025 hibernate 悲观锁、乐观锁 026 hibernate 操作树形...

    hibernate学习笔记

    hibernate多对一关联映射(Hibernate_Many2One) 7 hibernate一对一主键关联映射(单向关联Person----&gt;IdCard) 8 hibernate一对一主键关联映射(双向关联Person&lt;----&gt;IdCard) 9 hibernate一对一唯一外键关联映射...

    HibernateAPI中文版.chm

    5.1.10. 多对一(many-to-one) 5.1.11. 一对一 5.1.12. 自然ID(natural-id) 5.1.13. 组件(component), 动态组件(dynamic-component) 5.1.14. properties 5.1.15. 子类(subclass) 5.1.16. 连接的子类(joined-...

    hibernate3.2中文文档(chm格式)

    5.1.10. 多对一(many-to-one) 5.1.11. 一对一 5.1.12. 自然ID(natural-id) 5.1.13. 组件(component), 动态组件(dynamic-component) 5.1.14. properties 5.1.15. 子类(subclass) 5.1.16. 连接的子类(joined-...

    JSP开发之hibernate之单向多对一关联的实例

    JSP开发之hibernate之单向多对一关联的实例 一对多的基础上来测试单向多对一的关联 hibernate多对一的关联关系定义: 和单向一对多不同的是:一对多是在意的一方的一方定义set集合,在映射文件中 &lt;one xss=...

    Hibernate_Annotation关联映射

    多对一(Many-to-One) 使用@ManyToOne批注来实现多对一关联。 @ManyToOne批注有一个名为targetEntity的参数,该参数定义了目标实体名,通常不需要定义该参数,因为在大部分情况下默认值(表示关联关系的属性类型)就...

    Hibernate+中文文档

    5.1.10. 多对一(many-to-one) 5.1.11. 一对一 5.1.12. 自然ID(natural-id) 5.1.13. 组件(component), 动态组件(dynamic-component) 5.1.14. properties 5.1.15. 子类(subclass) 5.1.16. 连接的子类(joined-...

    Hibernate_3.2.0_符合Java习惯的关系数据库持久化

    5.1.10. 多对一(many-to-one) 5.1.11. 一对一 5.1.12. 自然ID(natural-id) 5.1.13. 组件(component), 动态组件(dynamic-component) 5.1.14. properties 5.1.15. 子类(subclass) 5.1.16. 连接的子类(joined-...

    Hibernate中文详细学习文档

    5.1.10. 多对一(many-to-one) 5.1.11. 一对一 5.1.12. 自然ID(natural-id) 5.1.13. 组件(component), 动态组件(dynamic-component) 5.1.14. properties 5.1.15. 子类(subclass) 5.1.16. 连接的子类(joined-...

    Hibernate 中文 html 帮助文档

    5.1.10. 多对一(many-to-one) 5.1.11. 一对一 5.1.12. 自然ID(natural-id) 5.1.13. 组件(component), 动态组件(dynamic-component) 5.1.14. properties 5.1.15. 子类(subclass) 5.1.16. 连接的子类(joined-...

    hibernate 体系结构与配置 参考文档(html)

    多对一(many-to-one) 5.1.11. 一对一 5.1.12. 自然ID(natural-id) 5.1.13. 组件(component), 动态组件(dynamic-component) 5.1.14. properties 5.1.15. 子类(subclass) 5.1.16. 连接的子类(joined-subclass...

    Hibernate3的帮助文档

    6.1.10. 多对一(many-to-one) 6.1.11. 一对一 6.1.12. 组件(component), 动态组件(dynamic-component) 6.1.13. properties 6.1.14. 子类(subclass) 6.1.15. 连接的子类(joined-subclass) 6.1.16. 联合子类...

    最全Hibernate 参考文档

    5.1.10. 多对一(many-to-one) 5.1.11. 一对一 5.1.12. 组件(component), 动态组件(dynamic-component) 5.1.13. properties 5.1.14. 子类(subclass) 5.1.15. 连接的子类(joined-subclass) 5.1.16. 联合子类(union-...

    Hibernate教程

    6.1.10. 多对一(many-to-one) 6.1.11. 一对一 6.1.12. 组件(component), 动态组件(dynamic-component) 6.1.13. properties 6.1.14. 子类(subclass) 6.1.15. 连接的子类(joined-subclass) 6.1.16. 联合子类...

    hibernate 框架详解

    多对一(many-to-one) 6.1.11. 一对一 6.1.12. 组件(component), 动态组件(dynamic-component) 6.1.13. properties 6.1.14. 子类(subclass) 6.1.15. 连接的子类(joined-subclass) 6.1.16. 联合子类(union-...

    hibernate3.04中文文档.chm

    6.1.10. 多对一(many-to-one) 6.1.11. 一对一 6.1.12. 组件(component), 动态组件(dynamic-component) 6.1.13. properties 6.1.14. 子类(subclass) 6.1.15. 连接的子类(joined-subclass) 6.1.16. 联合子类...

    Hibernate3+中文参考文档

    5.1.10. 多对一(many-to-one) 5.1.11. 一对一 5.1.12. 组件(component), 动态组件(dynamic-component) 5.1.13. properties 5.1.14. 子类(subclass) 5.1.15. 连接的子类(joined-subclass) 5.1.16. 联合子类(union-...

    Hibernate参考文档

    5.1.10. 多对一(many-to-one) 5.1.11. 一对一 5.1.12. 自然ID(natural-id) 5.1.13. 组件(component), 动态组件(dynamic-component) 5.1.14. properties 5.1.15. 子类(subclass) 5.1.16. 连接的子类(joined-...

    NHibernate中文文档

    值集合和多对多关联(Collections of Values and Many-To-Many Associations) 14 一对多关联(One-To-Many Associations) 14 延迟初始化(延迟加载)(Lazy Initialization) 14 集合排序(Sorted Collections) 14 使用 ...

    Pro JPA 2 Mastering the Java Persistence API free down

    JPA2.0 加入了大量必须的 ORM 映射增强特性,包括:支持通过使用 @ElementCollection 标注来增强 collections, maps 和 lists( 这里不是指实体之间的关联关系 ) 集合,支持 map 的单向 one-to-many 关联 (JPA1.0...

Global site tag (gtag.js) - Google Analytics