原文地址:http://www.2cto.com/kf/201410/340717.html
提到树状映射,许多人肯定会头疼死了,因为看树状这俩字就肯定想到会跟数据结构打交道,而数据结构是本科阶段最重要也是最难学的一门专业课。说实话摩罗我《数据结构》这门课学得也不咋滴,花了点时间终于完成了hibernate之树状映射这个小程序。
首先我先定义了个公司组织类(Org),一个组织下面可以有多个子组织,但每个组织都只有一个上级组织,也就是传说中的一对多的关系,但这个关系是双向的。提到双向关系,我们第一件事就是在双向关系的两边都要设双向关联,另外为了防止产生冗余,我们要在其中的一方设mappedBy,至于设在哪方,等下在下面的程序中解释。
既然确定了这个组织类(Org)是双向关系的,那么该如何定义这个类呢?首先从数据库表设计的角度来考虑一下,每个组织下面都可能有多个子组织,而每个子组织对应的只有一个上级组织,这是典型的一对多关系,一个组织拥有它自己的id以及组织名字(name),这俩已经可以描述这个组织了,但怎么描述各个组织之间的关系呢?也就是说在表里我们还必须定义字段去提现关系。因为是一对多的关系,一对多映射关系有一个规律很重要,那就是必须是在“多”的这方设置“一”的这方的外键,在这里就是在下级组织中设置上级组织的外键,这样通过这个外键我们就可以找到这个组织对应的上级组织是谁。有的同学可能会疑惑了:为什么非要在“多”的这方设置设置“一”的这方的外键呢?而不是反过来呢?来看看下面这个例子就会明白为什么要这样设置了。
注:以下是数据库表里的错误设计方法:
GroupId | GroupName | UserId |
1 | Group_1 | 1 |
1 | Group_1 | 2 |
UserId | UserName |
1 | moluo |
2 | xingzhe |
解释完数据库里表的设计方法,再来讲讲程序里Org这个类该如何定义。
首先Org这个类是一个组织,从面向对象的角度来考虑,它既有上级组织,也有下级组织,当然id和name这俩属性是必不可少的。另外更重要的是它的上级组织以及下级组织实际上也是一个组织,于是我就定义出了下面这个Org类:
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
package
com.hibernate.model;
import
java.util.HashSet;
import
java.util.Set;
import
javax.persistence.CascadeType;
import
javax.persistence.Entity;
import
javax.persistence.FetchType;
import
javax.persistence.GeneratedValue;
import
javax.persistence.Id;
import
javax.persistence.JoinColumn;
import
javax.persistence.ManyToOne;
import
javax.persistence.OneToMany;
import
javax.persistence.Table;
@Entity
@Table
(name=_Organization)
public
class
Org {
private
int
id;
private
String name;
private
Set<org> children =
new
HashSet<org>();
private
Org parent;
@Id
@GeneratedValue
public
int
getId() {
return
id;
}
public
void
setId(
int
id) {
this
.id = id;
}
public
String getName() {
return
name;
}
public
void
setName(String name) {
this
.name = name;
}
@OneToMany
(mappedBy=parent,cascade=CascadeType.ALL,fetch=FetchType.EAGER)
public
Set<org> getChildren() {
return
children;
}
public
void
setChildren(Set<org> children) {
this
.children = children;
}
@ManyToOne
@JoinColumn
(name=parent_id)
public
Org getParent() {
return
parent;
}
public
void
setParent(Org parent) {
this
.parent = parent;
}
}
</org></org></org></org>
|
再来解释一下cascade,该属性定义的是类与类之间的级联关系,定义的级联关系将被容器视为将当前类对象以及与之关联的类对象采取相同的操作,而且这种级联关系是递归的。cascade属性值有:ALL:表示所有情况都进行相同操作,即save、update、delete;PERSIST:这个表示在保存时采取相同的操作,MERGE是JPA的官方叫法,实际上就跟sava()一样;REMOVE:这个表示级联删除,实际上跟delete()方法一样;REFRESH:级联刷新。
接着解释一下fetch:fetch是读操作,它有俩属性,LAZY:表示只读取当前对象,关联对象不读;EAGER:当前对象被读取的时候,关联对象也会被读取,而且这种级联关系是递归的。
@OneToMany:表示当前这个类对象(实体)对应getXXX()方法表示的属性XXX对应的对象(实体)是一对多的关系。
@ManyToOne:表示当前这个类对象(实体)对应getXXX()方法表示的属性XXX对应的对象(实体)是多对一的关系。
@JoinColumn:用来注释表中的字段名字。
最后再来看看JUnit Test Case:
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
package
com.hibernate.model;
import
org.hibernate.Session;
import
org.hibernate.SessionFactory;
import
org.hibernate.cfg.AnnotationConfiguration;
import
org.hibernate.tool.hbm2ddl.SchemaExport;
import
org.junit.AfterClass;
import
org.junit.BeforeClass;
import
org.junit.Test;
public
class
TreeTest {
public
static
SessionFactory sf =
null
;
@BeforeClass
public
static
void
beforeClass(){
try
{
sf =
new
AnnotationConfiguration().configure().buildSessionFactory();
}
catch
(Exception e) {
e.printStackTrace();
}
finally
{
}
}
@Test
public
void
testSave() {
Org o =
new
Org();
o.setName(总公司);
Org o1 =
new
Org();
o1.setName(分公司
1
);
Org o2 =
new
Org();
o2.setName(分公司
2
);
Org o11 =
new
Org();
o11.setName(分公司
1
下的部门
1
);
Org o12 =
new
Org();
o12.setName(分公司
1
下的部门
2
);
Org o21 =
new
Org();
o21.setName(分公司
2
下的部门
1
);
o.getChildren().add(o1);
o.getChildren().add(o2);
o1.getChildren().add(o11);
o1.getChildren().add(o12);
o12.getChildren().add(o21);
o1.setParent(o);
o2.setParent(o);
o11.setParent(o1);
o12.setParent(o1);
o21.setParent(o2);
Session session = sf.getCurrentSession();
session.beginTransaction();
session.save(o);
session.getTransaction().commit();
}
@Test
public
void
testLoad() {
testSave();
Session session = sf.getCurrentSession();
session.beginTransaction();
Org o = (Org)session.load(Org.
class
,
1
);
print(o,
0
);
session.getTransaction().commit();
}
private
void
print(Org o,
int
level) {
String preStr = ;
for
(
int
i=
0
; i<level; afterclass=
""
for
=
""
new
=
""
org=
""
pre=
""
prestr=
""
public
=
""
static
=
""
test=
""
void
=
""
>里面定义了个print()方法,里面那个level是为了使打印结果呈现树状结构<p> </p><p>打印结果:</p><p> </p><pre
class
=
"brush:java;"
>总公司
_分公司
2
__分公司
2
下的部门
1
_分公司
1
__分公司
1
下的部门
2
__分公司
1
下的部门
1
</pre>
<p> </p>
<p> </p>
<br>
<br>
<p> </p>
<p> </p>
</level;><br>
|