`

Hibernate 多对一关联配置

阅读更多
实体是Employee和Department,它们之间是多对一的关系。

Department类:
public class Department {
	private int id;
	private String name;

	public Department() {
	}
	public Department(String name) {
		this.name = name;
	}
	// getters and setters are omitted
}


Employee类:
public class Employee {
	private int id;
	private String name;
	private Department department;

	public Employee() {
	}
	public Employee(String name) {
		this.name = name;
	}
	// getters and setters are omitted


Department.hbm.xml:
<hibernate-mapping
	package="com.john.myhibernate.domain">

	<class name="Department">
		<id name="id">
			<generator class="native"/>
		</id>
		<property name="name" length="20" not-null="true"/>
	</class>
</hibernate-mapping>


Employee.hbm.xml:
<hibernate-mapping package="com.john.myhibernate.domain">

<class name="Employee">
	<id name="id">
		<generator class="native"/>
	</id>
	<property name="name" length="20" not-null="true"/>
	<many-to-one name="department" column="department_id" class="Department" fetch="select"/>
</class>
</hibernate-mapping>

many-to-one没有inverse属性,因为关系的维护是many的一方,不可能放弃对关系的维护。
many-to-one的lazy属性有三个取值:false, proxy, no-proxy。

1. 测试cascade属性:
	public void testSaveCascade() {
		Session s = null;
		Transaction tx = null;
		
		Department depart = new Department();
		depart.setName("FCI");
		
		Employee em1 = new Employee("John");
		em1.setDepartment(depart);
		
		Employee em2 = new Employee("Lucy");
		em2.setDepartment(depart);
		
		try {
			s = HibernateUtil.getSession();
			tx = s.beginTransaction();
			s.save(em1);
			s.save(em2);
			tx.commit();
		} catch (HibernateException e) {
			tx.rollback();
			e.printStackTrace();
		} finally {
			if (s != null)
				s.close();
		}
	}

结果是报org.hibernate.TransientObjectException异常,因为没有保存Department实例。

可以加cascade属性,解决问题:
<many-to-one name="department" column="department_id" class="Department" fetch="select" cascade="save-update"/>


2. 测试fetch
	Session s = null;
	
	s = HibernateUtil.getSession();
	Employee em = (Employee) s.get(Employee.class, 2);
	System.out.println(em.getName());
	System.out.println(em.getDepartment());

查询语句如下:
Hibernate: select employee0_.id as id1_0_, employee0_.name as name1_0_, employee0_.department as department1_0_, employee0_.skill as skill1_0_, employee0_.sell as sell1_0_, employee0_.type as type1_0_ from Employee employee0_ where employee0_.id=?

Hibernate: select department0_.id as id0_0_, department0_.name as name0_0_ from Department department0_ where department0_.id=?
因为fetch设置为select,所以对每个实体,都分别用一个SELECT语句

如果把fetch设置为join,也就是连表查询,只使用一个SELECT语句。如下:
Hibernate: select employee0_.id as id1_1_, employee0_.name as name1_1_, employee0_.department as department1_1_, employee0_.skill as skill1_1_, employee0_.sell as sell1_1_, employee0_.type as type1_1_, department1_.id as id0_0_, department1_.name as name0_0_ from Employee employee0_ left outer join Department department1_ on employee0_.department=department1_.id where employee0_.id=?

3. 测试lazy
当fetch为select时,设置lazy为proxy或者no-proxy。
<many-to-one name="department" column="department_id" class="Department" fetch="select" cascade="save-update" lazy="no-proxy"/>

	Session s = null;
	
	s = HibernateUtil.getSession();
	Employee em = (Employee) s.get(Employee.class, 2);
	s.close();
	System.out.println(em.getName());
	System.out.println(em.getDepartment());

结果是报org.hibernate.LazyInitializationException异常。
因为fetch为select,而且lazy为proxy或者no-proxy,所以开始仅仅查询Employee,当需要用SELECT语句查询Department时,Session已经关闭。

解决办法:
1. 设置lazy为false,hibernate会第一时间把Employee和Department查询出来。
   如果fetch为select,使用两个SELECT查询语句。
   如果fetch为join,使用一个SELECT连表查询语句。
2. 设置fetch为join,这时不管lazy的取值,hibernate会进行连表查询,把两个实体都查询出来。
分享到:
评论
2 楼 Hibernate1 2016-08-04  
讲解的很不错,收益了。感谢发表者;
1 楼 5dyoyo 2014-07-08  
[img][list]
[*]

[/list][/img]

相关推荐

Global site tag (gtag.js) - Google Analytics