Hibernate 的关联映射,包括单向多对一关联、单向一对多关联、双向多对一关联、双向一对一关联、多对多关联。
双向多对一
单向多对一映射:由 “多(作为从表,建立外键)” 的一方指向 “一(作为主表)” 的一方。例如,图书信息表 books 和出版社信息表 publishers 的对应关系就是一种多对一关系。
单向一对多映射:Books 对 Publishers 是单向多对一关联,反过来看,Publishers 对 Books 就是单向一对多关联,即一个出版社可以出版多本图书。意味着每个 Publishers 对象会引用一组 Books 对象,因此在 Publishers 类中定义一个集合类型的属性,在访问 “一” 的一方 Publishers 对象时,关联的 “多” 的一方 Books 的多个对象将保存到该集合类型的属性中。
把单向多对一和单向一对多两者集合起来,就形成了双向关联。在实体类中,把类 Books 的 PublisherId 单独作为一个类变量,使用 @ManyToOne
和 @JoinColumn
注解实现 Books
到 Publishers
的多对一关系。
基于 Annotation 注解实现的实体类 Books:1
2
3
4
5
6
7
8
9
10
11//定义 Publishers 类型的关联属性
private Publishers publishers;
//使用 @ManyToOne 和 @JoinColumn 注解实现 Books 到 Publishers 的多对一关联
@ManyToOne(fethch=FetchType.EAGER)
@Cascade(value={ CascadeType.SAVE_UPDATE })
@JoinColumn(name="PublisherId")
public Publishers getPublishers()
{
return publishers;
}
注:
@ManyToOne
注解的属性fetch
属性的可选择项包括FetchType.EAGER
和FetchType.LAZY
,前者表示加载 Books 对象时就会同时加载关联的 Publishers 对象,后者表示延迟加载,默认值是FetchType.LAZY
。@Cascade(value={CascadeType.SAVE_UPDATE})
注解指定类与类之间的级联关系,主类执行保存或更新操作时,关联类执行同样的操作。@JoinColumn(name="PublicsherId")
指定数据表 books 的 PublisherId 字段作为外键与数据表 pubishers 的主键关联。
基于 Annotation 注解实现的实体类 Publishers:1
2
3
4
5
6
7
8
9
10//定义元素类型为 Books 的关联集合属性 bks
private Set<Books> bks=new HashSet<>();
//使用 @OneToMany 注解实现 Publishers 到 Books 的一对多关联
@OneToMany(mappedBy="publishers",fetch=FetchType.EAGER)
@Cascade(value={CascadeType.DELETE})
public Set<Books> getBks()
{
return bks;
}
注:
@OneToMany
注解的mappedBy
属性的作用相当于设置inverse=true
,表示将关联关系的主管权反转,即由 Books 管理关联关系,mappedBy
的属性值为关联的多的一方(Books类)所定义的 Publicshers 类型的属性(publishers)。@Cascade(value={ CascadeType.DELETE }
注解指定级联删除。
双向一对一关联映射
一对一关联 可以分为 基于外键的一对一关联 和 基于主键的一对一关联。
基于外键的一对一映射
基于外键的一对一关联与多对一关联实质相同,是多对一关联的一个特例。特别之处在于在表示 “多” 的从表中外键必须是 unique。例如,公民表 people 和身份证表 identitycard 的关系属于一对一关联。公民表 people 的 CardId 字段作为外键,必须保证唯一。
基于主键的一对一映射
基于主键的一对一关联就是限制两个数据表的主键使用相同的值,通过主键形成一对一映射关联,根据对方主键生成自己的主键。
基于 Annotation 注解实现的持久化类 PeopleZj 的代码: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@Entity
@Table(name="people_zj",catalog="bookshop")
public class PeopleZj
{
private Integer id;
private String name;
private String sex;
//定义 IdentitycardZj 类型关联属性
private IdenttitycardZj identitycardZj;
//定义默认构造器以及不含 identitycardZj 成员变量的构造器
public PeopleZj() {}
public PeopleZj(String name,String sex,Integer age)
{
this.name=name;
this.sex=sex;
this.age=age;
}
//以下注解的功能是将当前对象中 identitycardZj 属性的主键来作为本对象的主键
@GenericGenerator(name="generator",strategy="foreign",parameter=@Parameter(name="property",value="identitycardZj"))
@Id
@GeneratedValue(generator="generator")
@Column(name="Id",unique=true,nullable=false)
public Integer getId()
{
return this.id;
}
//使用 @OneToMany 注解实现 PeopleZj 与 IdentitycardZj 的基于主键的一对一关联
@OneToMany(mappedBy="peopleZj",optional=false)
public IdentitycardZj getIdentitycardZj()
{
return identitycardZj;
}
@GenericGenerator
注解声明了一个 Hibernate 的主键生成策略,该注解的 name 属性指定生成器名称,strategy 属性指定具体生成器的类名(即生成策略),这里选择 foreign 策略,表示使用另一个关联对象的主键。parameter 属性得到 strategy 指定的具体生成器所用到的参数,设置 values=”identitycardZj”,表示将当前类 PeopleZj 中定义的 IdentitycardZj 类型的 identitycardZj 属性的主键作为 PeopeZj 类对象的主键。
基于 Annotation 注解实现的持久化类 IdentitycardZj 的代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18@Entity
@Table(name="identitycard_zj",catalog="bookshop")
public class IdentitycardZj
{
private Integer id;
private String cardNo;
//定义 PeopleZj 类型的关联属性
private PeopleZj peopleZj;
//使用 @OneToOne 和 @PrimaryKeyJoinColumn 注解
//实现 IdentitycardZj 与 PeopleZj 的基于注解的一对一关联
@OntToOne(cascade=CascadeType.ALL)
@PrimaryKeyJoinColumn
public PeopleZj getPeopleZj()
{
return peopleZj;
}
属性 cascade=CascadeType.ALL 表示 IdentitycardZj 类执行的所有操作 PeolpleZj 都会级联执行。
@PrimaryKeyJoinColumn
表示两个实体类通过主键关联
多对多关联映射
一个学生可以选择多个课程,而一门课程可以被多个学生选择,这样就形成了多对多关联。
可以通过一个中间表来维护两者之间的多对多关联。
sc 表以 Sid 和 Cid 作为 联合主键,其中,Sid 字段作为外键指向 Student 表,Cid 字段作为外键指向 Course 表。1
2
3
4alter table sc
add constraint FK_Sid foreign key sc(Sid) references student(StudentId)
alter table sc
add constraint FK_Cid foreign key sc(Cid) references course(CourseId)
基于 Annotation 注解实现的持久化类 Course 的代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16@Entity
@Table(name="course",catalog="bookshop")
public class Course
{
private Integer courseId;
private String courseName;
//定义元素类型为 Student 的选课学生集合 students
private Set<Student> students = new HashSet<>();
//使用 @ManyToMany 注解实现 Course 到 Student 的多对多关联
@ManyToMany(mappedBy="course",fethch=FetchType.EAGER)
public Set<Student> getStudent()
{
return students;
}
基于 Annotation 注解实现的持久化类 Student 的代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18@Entity
@Table(name="student",catalog="bookshop")
public class Student
{
private Integer studentId;
private String studentName;
//定义元素类型为 Course 的选修课程集合
private Set<Course> courses = new HashSet<>();
//使用 @ManyToMany 注解实现 Student 到 Course 的多对多关联
@ManyToMany(fetch=FetchType.EAGER)
@Cascade(value={ CascadeType.SAVE_UPDATE }
@JoinTable(name="sc",joinColumns={ @JoinColumn(name="Sid"),inverseJoinColumn={@JoinColumn(name="Cid")} }
public Set<Course> getCourse()
{
return courses;
}
@JoinTable
注解描述了多对多关系的数据表关系,name 属性指定中间表的名称,这里为 “sc”;joinColumns 属性定义了中间表 sc 与学生表 student 关联的外键列,这里为 “Sid”;inverseJoinColumns 属性定义中间表 sc 与另一端课程表 course 关联的外键列 ,这里为 “Cid”。