1、关联映射如何处理业务逻辑
2、如何指定中间表
3、如何进行级联操作
4、如何解决Hibenrate建表过程中主键错乱问题
现在有三张表
Student(学生表),Course(课程表),Score(学生,课程,分数,表)
那么我们分析业务逻辑可知,学生和课程是多对多的关系,学生和分数表是一对多的关系,课程和分数也是一对多的关系。
直接看Annotations配置,在这里我所有的配置都是双向关联,这样在分数,课程,学生,之中,可以任意找到彼此!
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
|
@Entity
@Table
(name=
"c_course"
)
public
class
Course {
private
Integer id;
private
String coursename;
private
Set<Student> students=
new
HashSet<Student>();
private
Set<Score> scores=
new
HashSet<Score>();
@OneToMany
(mappedBy=
"course"
)
//必须指定关系由多的一方维护
public
Set<Score> getScores() {
return
scores;
}
public
void
setScores(Set<Score> scores) {
this
.scores = scores;
}
@ManyToMany
//指定中间表是s_score
@JoinTable
(name=
"s_score"
,joinColumns={
@JoinColumn
(name=
"course_id"
)},
inverseJoinColumns={
@JoinColumn
(name=
"student_id"
)})
public
Set<Student> getStudents() {
return
students;
}
public
void
setStudents(Set<Student> students) {
this
.students = students;
}
@Id
@GeneratedValue
public
Integer getId() {
return
id;
}
public
void
setId(Integer id) {
this
.id = id;
}
@Column
(name=
"c_coursename"
)
public
String getCoursename() {
return
coursename;
}
public
void
setCoursename(String coursename) {
this
.coursename = coursename;
}
}
|
(课程表Course)
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
|
@Entity
@Table
(name=
"t_student"
)
public
class
Student {
private
Integer id;
private
String name;
private
Set<Course> courses=
new
HashSet<Course>();
private
Set<Score> scores=
new
HashSet<Score>();
@OneToMany
(mappedBy=
"student"
)
public
Set<Score> getScores() {
return
scores;
}
public
void
setScores(Set<Score> scores) {
this
.scores = scores;
}
@ManyToMany
@JoinTable
(name=
"s_score"
,joinColumns={
@JoinColumn
(name=
"student_id"
)},
inverseJoinColumns={
@JoinColumn
(name=
"course_id"
)})
public
Set<Course> getCourses() {
return
courses;
}
public
void
setCourses(Set<Course> courses) {
this
.courses = courses;
}
@Id
@GeneratedValue
public
Integer getId() {
return
id;
}
public
void
setId(Integer id) {
this
.id = id;
}
@Column
(name=
"s_name"
)
public
String getName() {
return
name;
}
public
void
setName(String name) {
this
.name = name;
}
}
|
(Student学生表)
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
|
@Entity
@Table
(name=
"s_score"
)
public
class
Score {
private
Integer id;
private
String score;
private
Student student;
private
Course course;
@ManyToOne
(cascade={CascadeType.ALL})
//配置级联操作
@JoinColumn
(name=
"student_id"
)
public
Student getStudent() {
return
student;
}
public
void
setStudent(Student student) {
this
.student = student;
}
@ManyToOne
(cascade={CascadeType.ALL})
@JoinColumn
(name=
"course_id"
)
public
Course getCourse() {
return
course;
}
public
void
setCourse(Course course) {
this
.course = course;
}
@Id
@GeneratedValue
public
Integer getId() {
return
id;
}
public
void
setId(Integer id) {
this
.id = id;
}
@Column
(name=
"s_score"
)
public
String getScore() {
return
score;
}
public
void
setScore(String score) {
this
.score = score;
}
}
|
(分数表,也是中间关联表,Score)
那么问题来了,采用Hibernate自动建表,我们看一下建表语句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
12:11:08,169 DEBUG SchemaExport:415 -
create
table
c_course (
id
integer
not
null
auto_increment,
c_coursename
varchar
(255),
primary
key
(id)
)
12:11:08,333 DEBUG SchemaExport:415 -
create
table
s_score (
id
integer
not
null
,
s_score
varchar
(255),
course_id
integer
,
student_id
integer
not
null
auto_increment,
primary
key
(student_id, course_id)
)
12:11:08,455 DEBUG SchemaExport:415 -
create
table
t_student (
id
integer
not
null
auto_increment,
s_name
varchar
(255),
primary
key
(id)
)
|
我们发现在建表是Hibernate默认将student_id和course_id联合作为主键使用,且student_id还是自增
这样显然是不对的,在这里我也实在想不到,好的办法,智能采用一个笨的办法,手动改回来!
大家最好是采用工具操作,因为,你直接create的话,student_id和course_id关联不上student,course的主键ID
ok,到这里,我们的建表基本完成,下面JunitTest
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
|
@Test
public
void
add(){
try
{
Configuration cfg=
new
Configuration();
cfg.configure();
SessionFactory sessionFactory=cfg.buildSessionFactory();
Session session=sessionFactory.openSession();
session.beginTransaction();
Student student1=
new
Student();
student1.setName(
"张三1"
);
// Student student2=new Student();
// student2.setName("李四");
Course c1=
new
Course();
c1.setCoursename(
"数学1"
);
Course c2=
new
Course();
c2.setCoursename(
"语文1"
);
// session.save(student1);
// session.save(c1);
// session.save(student2);
// session.save(c2);
Score score=
new
Score();
score.setScore(
"901"
);
score.setCourse(c1);
score.setStudent(student1);
//张三数学90分
session.save(score);
Score score2=
new
Score();
score2.setCourse(c2);
score2.setScore(
"100"
);
score2.setStudent(student1);
session.save(score2);
session.getTransaction().commit();
session.close();
sessionFactory.close();
}
catch
(HibernateException e) {
e.printStackTrace();
}
}
|
ok,大家可以看出,为什么我们最后只需要保存score就行呢?没有session.save()student和course,为什么也能直接保存数据库中?这就是
1
|
cascade={CascadeType.ALL}
|
级联操作,当然我这里配置的是ALL,其实还有4个参数,大家可以自己慢慢研究!
以上添加成功,那么我们直接load试一下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public
void
findTest(){
Configuration cfg=
new
Configuration();
cfg.configure();
SessionFactory sessionFactory=cfg.buildSessionFactory();
Session s=sessionFactory.openSession();
s.beginTransaction();
Student student=(Student)s.load(Student.
class
,
2
);
System.out.println(
"学生姓名"
+student.getName());
for
(Course course:student.getCourses()){
System.out.print(
"--------"
+
"课程名称"
+course.getCoursename());
for
(Score score:course.getScores()){
System.out.println(
"--------"
+
"课程分数"
+score.getScore());
}
}
s.getTransaction().commit();
s.close();
sessionFactory.close();
}
|
也没问题
update呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public
void
update(){
Configuration cfg=
new
Configuration();
cfg.configure();
SessionFactory sessionFactory=cfg.buildSessionFactory();
Session s=sessionFactory.openSession();
s.beginTransaction();
Student student=(Student)s.load(Student.
class
,
1
);
//我们现在把查询出来语文成绩改为0分
for
(Course course:student.getCourses()){
System.out.println(course.getCoursename());
if
(
"语文"
.equals(course.getCoursename())){
for
(Score score:course.getScores()){
if
(score.getStudent().getId().equals(student.getId())){
score.setScore(
"0"
);
s.update(score);
}
}
}
}
s.getTransaction().commit();
s.close();
sessionFactory.close();
}
|
删除?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@Test
public
void
deleteObj(){
Configuration cfg=
new
Configuration();
cfg.configure();
SessionFactory sessionFactory=cfg.buildSessionFactory();
Session s=sessionFactory.openSession();
s.beginTransaction();
Student student=(Student)s.load(Student.
class
,
3
);
s.delete(student);
s.getTransaction().commit();
s.close();
sessionFactory.close();
}
|
ok,到这里基本上,完成Hibernate关联映射的基本操作!
注意,多对多删除的时候,我们一般删除的是中间表数据?但是往往由于外键关联的关系,Hibernate会删除另一张表中的数据来解除关联关系,这就不对了!后续再探讨!