Hibernate学习之一对一映射

#基于外键的一对一关联关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.mamh.hibernate.demo.entities;

public class Department {
private int depatmentId;
private String departmentName;

private Manager manager;

public Manager getManager() {
return manager;
}

public void setManager(Manager manager) {
this.manager = manager;
}

public int getDepatmentId() {
return depatmentId;
}

public void setDepatmentId(int depatmentId) {
this.depatmentId = depatmentId;
}

public String getDepartmentName() {
return departmentName;
}

public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.mamh.hibernate.demo.entities;

public class Manager {
private int managerId;
private String managerName;

private Department department;

public Department getDepartment() {
return department;
}

public void setDepartment(Department department) {
this.department = department;
}

public int getManagerId() {
return managerId;
}

public void setManagerId(int managerId) {
this.managerId = managerId;
}

public String getManagerName() {
return managerName;
}

public void setManagerName(String managerName) {
this.managerName = managerName;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.mamh.hibernate.demo.entities">

<class name="Department" table="hb_department" schema="mage">
<id name="depatmentId">
<column name="hb_department_id" sql-type="int(11)"/>
<generator class="native"/>
</id>
<property name="departmentName" type="string">
<column name="hb_department_name"/>
</property>

<!-- 使用many to one 方式来映射一对一关联关系 -->
<many-to-one name="manager" class="Manager" column="hb_manager_id" unique="true" />


</class>
</hibernate-mapping>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.mamh.hibernate.demo.entities">

<class name="Manager" table="hb_manager" schema="mage">
<id name="managerId">
<column name="hb_manager_id" sql-type="int(11)"/>
<generator class="native"/>
</id>
<property name="managerName" type="string">
<column name="hb_manager_name"/>
</property>

<!--映射1to1,关联关系 -->
<one-to-one name="department" class="Department"/>

</class>
</hibernate-mapping>

保存操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

@Test
public void testDepartment(){
Department department = new Department();
department.setDepartmentName("dept-aaa");

Manager manager = new Manager();
manager.setManagerName("mgr-aaa");

manager.setDepartment(department);
department.setManager(manager);

//建议先保存没有外键的那个对象。这样会减少update语句。
session.save(manager);
session.save(department);


}

查询操作

1
2
3
4
5
6
@Test
public void testGetDepartment() {
Department department = (Department) session.get(Department.class, 1);
System.out.println(department.getDepartmentName());

}

默认情况下会使用懒加载。如果这里不访问manager的话就不会去查询manager对象。

1
2
3
4
5
6
7
8
9
10
11
Hibernate: 
select
department0_.hb_department_id as hb1_4_0_,
department0_.hb_department_name as hb2_4_0_,
department0_.hb_manager_id as hb3_4_0_
from
atguigu.hb_department department0_
where
department0_.hb_department_id=?

dept-aa

这里我继续,来查询一些manager对象。

1
2
3
4
5
6
@Test
public void testGetDepartment() {
Department department = (Department) session.get(Department.class, 1);
System.out.println(department.getManager());

}

但是我们发现所使用的sql有点问题
开始查询department是没问题,查manager使用了left outer join左外连接。发现链接条件不对。
查询条件应该是department.manger_Id = manager.manger_id.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Hibernate: 
select
department0_.hb_department_id as hb1_4_0_,
department0_.hb_department_name as hb2_4_0_,
department0_.hb_manager_id as hb3_4_0_
from
atguigu.hb_department department0_
where
department0_.hb_department_id=?
Hibernate:
select
manager0_.hb_manager_id as hb1_5_1_,
manager0_.hb_manager_name as hb2_5_1_,
department1_.hb_department_id as hb1_4_0_,
department1_.hb_department_name as hb2_4_0_,
department1_.hb_manager_id as hb3_4_0_
from
atguigu.hb_manager manager0_
left outer join
atguigu.hb_department department1_
on manager0_.hb_manager_id=department1_.hb_department_id
where
manager0_.hb_manager_id=?
com.mamh.hibernate.demo.entities.Manager@64ec96c6
=destroy=

正确的做法是:配置一个property-ref属性。

1
<one-to-one name="department" class="Department" property-ref="manager"/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Hibernate: 
select
department0_.hb_department_id as hb1_4_0_,
department0_.hb_department_name as hb2_4_0_,
department0_.hb_manager_id as hb3_4_0_
from
atguigu.hb_department department0_
where
department0_.hb_department_id=?
Hibernate:
select
manager0_.hb_manager_id as hb1_5_1_,
manager0_.hb_manager_name as hb2_5_1_,
department1_.hb_department_id as hb1_4_0_,
department1_.hb_department_name as hb2_4_0_,
department1_.hb_manager_id as hb3_4_0_
from
atguigu.hb_manager manager0_
left outer join
atguigu.hb_department department1_
on manager0_.hb_manager_id=department1_.hb_manager_id
where
manager0_.hb_manager_id=?
Hibernate:
select
department0_.hb_department_id as hb1_4_0_,
department0_.hb_department_name as hb2_4_0_,
department0_.hb_manager_id as hb3_4_0_
from
atguigu.hb_department department0_
where
department0_.hb_manager_id=?
com.mamh.hibernate.demo.entities.Manager@456d6c1e
=destroy=

没有外键的这一端,也就是manager这一端,需要设置property-ref来使用主键以外的列作为关联。

我们来测试单独查询manager会是咋样的?
我们发现查询manager的时候,也就是查询没有外键的那个对象会使用左外连接,
一并查出其关联的对象,并一起进行初始化。

1
2
3
4
5
@Test
public void testGetManager() {
Manager manager = (Manager) session.get(Manager.class, 1);
System.out.println(manager);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Hibernate: 
select
manager0_.hb_manager_id as hb1_5_1_,
manager0_.hb_manager_name as hb2_5_1_,
department1_.hb_department_id as hb1_4_0_,
department1_.hb_department_name as hb2_4_0_,
department1_.hb_manager_id as hb3_4_0_
from
atguigu.hb_manager manager0_
left outer join
atguigu.hb_department department1_
on manager0_.hb_manager_id=department1_.hb_manager_id
where
manager0_.hb_manager_id=?

com.mamh.hibernate.demo.entities.Manager@2ca26d77
=destroy=

最后:不要两个表里都使用一个外键来关联另外的一个对象。


#基于主键的一对一关联关系

两张表的主键一样就是基于主键的一对一映射
Department 类和Manager类还是那个类,代码不变

hbm配置映射文件需要改动一下

在department.hbm.xml中使用one to one来映射,同时要使用constrained=”true”属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<hibernate-mapping package="com.mamh.hibernate.demo.entities">

<class name="Department" table="hb_department" schema="atguigu">
<id name="depatmentId">
<column name="hb_department_id" sql-type="int(11)"/>
<generator class="foreign">
<param name="property">manager</param>
</generator>
</id>
<property name="departmentName" type="string">
<column name="hb_department_name"/>
</property>

<!-- 使用one to one 方式来映射一对一关联关系 -->
<!-- 采用foreign主键生成器的一端需要设置constrainend=true -->
<one-to-one name="manager" class="Manager" constrained="true"/>


</class>
</hibernate-mapping>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<hibernate-mapping package="com.mamh.hibernate.demo.entities">

<class name="Manager" table="hb_manager" schema="atguigu">
<id name="managerId">
<column name="hb_manager_id" sql-type="int(11)"/>
<generator class="native"/>
</id>
<property name="managerName" type="string">
<column name="hb_manager_name"/>
</property>

<!--映射1to1,关联关系 -->
<one-to-one name="department" class="Department" />

</class>
</hibernate-mapping>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void testSaveDepartment() {
Department department = new Department();
department.setDepartmentName("dept-aaa");

Manager manager = new Manager();
manager.setManagerName("mgr-aaa");

manager.setDepartment(department);
department.setManager(manager);

//先插入manager,然后插入department。这2个调换顺序也是一样的,应为department的主键是有manager决定的,所以要先插入manager。
session.save(manager);
session.save(department);


}
1
2
3
4
5
6
7

Hibernate:
insert into atguigu.hb_manager (hb_manager_name) values (?)
=destroy=
Hibernate:
insert into atguigu.hb_department (hb_department_name, hb_department_id)
values (?, ?)

查询操作

查询department

1
2
3
4
5
6
@Test
public void testGetDepartment() {
Department department = (Department) session.get(Department.class, 1);
System.out.println(department.getDepartmentName());

}
1
2
3
4
5
6
7
8
9
Hibernate: 
select
department0_.hb_department_id as hb1_4_0_,
department0_.hb_department_name as hb2_4_0_
from
atguigu.hb_department department0_
where
department0_.hb_department_id=?
dept-aaa

查询manager
此时会使用一个左外连接来查询,会连带department也查询出来。

1
2
3
4
5
@Test
public void testGetManager() {
Manager manager = (Manager) session.get(Manager.class, 1);
System.out.println(manager.getManagerName());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Hibernate: 
select
manager0_.hb_manager_id as hb1_5_1_,
manager0_.hb_manager_name as hb2_5_1_,
department1_.hb_department_id as hb1_4_0_,
department1_.hb_department_name as hb2_4_0_
from
atguigu.hb_manager manager0_
left outer join
atguigu.hb_department department1_
on manager0_.hb_manager_id=department1_.hb_department_id
where
manager0_.hb_manager_id=?
mgr-aaa
=destroy=