注解方式讲解映射关系
1 One-To-One Unidirectional with Foreign Key
单向关联外键方式。
1.1 关系如下
学生和地址关系的例子。一个学生住在一个地址上。一个地址只能由一个学生占用。
1.2 Address代码:
package com.daodaofun.domain; import javax.persistence.*; @Entity @Table(name="STUDENT") public class Student { @Id @GeneratedValue @Column(name="STUDENT_ID") private Long id; @Column(name = "FIRST_NAME") private String firstName; @Column(name = "LAST_NAME") private String lastName; @OneToOne @JoinColumn(name = "ADDRESS_ID") private Address address; public Student() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } }
这样可以不用写hbm.xml,还是挺方便的。此时注意在Student一端配置了JoinColumn,也就是关联的列,那么就会在Student表当中添加home_address_id这一列,作为外键。
外键名称如果需要指定可以使用@Foreignkey,遗憾的是这个版本已经是过时了,JPA的注解没有过时,但是无法加在这个属性之上,所以要么使用过时的注解,要么你忍受,或者你自行建表。
2 One-To-One Bidirectianal
所谓的双向配置也差不了多少,就是在另外一端一样加上引用即可,即在Address这一段一样持有Student。并且加上如下注解即可:
@OneToOne
private Student student;
但是这样有个问题,会导致双外键,这个明显属于冗余,这个时候我们需要指明谁来主导,外键由谁来建设的问题,所以我们需要额外设置一下如下:
@OneToOne(mappedBy = "address")
private Student student;
这样就比较合理了。
3 Many-To-One Bidirectional
多对一双向
我们以学生与大学的关系为例,一所大学可以有很多学生。
关系图如下:
3.1 University代码:
-··在一的一方配置OneToMany,同样的由于我们会将外键设置在多的一方,所以要将这个建设权交给对方,所以要加上mappedBy。
package com.daodaofun.domain; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity @Table(name="UNIVERSITY") public class University { @Id @GeneratedValue @Column(name="UNIVERSITY_ID") private Long id; @Column(name="NAME") private String name; @Column(name="COUNTRY") private String country; @OneToMany(mappedBy = "university",cascade = CascadeType.ALL) private List<Student> students; public University() { } public University(String name, String country) { this.name = name; this.country = country; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public List<Student> getStudents() { return students; } public void setStudents(List<Student> students) { this.students = students; } }
3.2 Student代码:
package com.daodaofun.domain; import javax.persistence.*; @Entity @Table(name="STUDENT") public class Student { @Id @GeneratedValue @Column(name="STUDENT_ID") private Long id; @Column(name = "FIRST_NAME") private String firstName; @Column(name = "LAST_NAME") private String lastName; @ManyToOne(optional = false) @JoinColumn(name = "UNIVERSITY_ID") private University university; public Student() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public University getUniversity() { return university; } public void setUniversity(University university) { this.university = university; } }
在多的一方,同样的指明建设外键是什么列加上JoinColumn,此外这里有一个optional=false,这个是什么含义呢?
(Optional) Whether the association is optional. If set
to false then a non-null relationship must always exist.
关联关系是否可选,如果设置为了false,那么就必须为非空关系。
4 Many-To-Many Bidirectional
双向多对多
在多对多关联中,使用了一个额外的表(称为联接表),其主键是两个关联表的主键的组合。换句话说,联接表和关联表之间存在外键关联表。
讨论一个学生和学科关系的例子。一名学生可以注册多个科目。一个科目可以有多个学生注册。
关系图如下:
向这种多多关系其实都是通过一张中间表来体现的。
4.1 Student代码:
package com.daodaofun.domain; import javax.persistence.*; import java.util.ArrayList; import java.util.List; @Entity @Table(name="STUDENT") public class Student { @Id @GeneratedValue @Column(name="STUDENT_ID") private Long id; @Column(name = "FIRST_NAME") private String firstName; @Column(name = "LAST_NAME") private String lastName; @ManyToMany(cascade = CascadeType.ALL) @JoinTable(name = "STUDENT_SUBJECT",joinColumns = {@JoinColumn(name = "STUDENT_ID")}, inverseJoinColumns = {@JoinColumn(name = "SUBJECT_ID")}) private List<Subject> subjects = new ArrayList<>(); public Student() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public List<Subject> getSubjects() { return subjects; } public void setSubjects(List<Subject> subjects) { this.subjects = subjects; } }
4.2 subject代码:
package com.daodaofun.domain; import javax.persistence.*; import java.util.ArrayList; import java.util.List; @Entity @Table(name = "SUBJECT") public class Subject { @Id @GeneratedValue @Column(name = "SUBJECT_ID") private Long id; @Column(name = "name") private String name; @ManyToMany(mappedBy = "subjects") private List<Student> students = new ArrayList<>(); public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Student> getStudents() { return students; } public void setStudents(List<Student> students) { this.students = students; } }
这里可以指定任意一方来负责设置表的生成方式,此处是由subjects来设置,需要注意的是
@JoinTable(name = "STUDENT_SUBJECT",joinColumns = {@JoinColumn(name = "STUDENT_ID")},
inverseJoinColumns = {@JoinColumn(name = "SUBJECT_ID")})通过name指定了中间表名称,然后指明需要生成的列,两列就是student表和subject表各自的主键。
以上几种是比较实用的映射关系方式,hibernate可以配置映射的方式特别多,上面几种差不多够用了。