JPA关联关系映射

JavaEE API文档:http://docs.oracle.com/javaee/7/api/

关联关系从整体上分为单向关联和双向关联
  • 单向关联:只需从一端访问另一端,如教师Teacher可访问学生Student,则Teacher实体需要包含类型为Student的属性
  • 双向关联:两端均可互相访问,如教师Teacher可访问学生Student,学生Student也可访问教师Teacher,两个实体均需要包含类型为对方的属性
关联关系细分为如下几种
  • 单向1-1:需要在控制关系的一方实体中使用注解@OneToOne、@JoinColumn标注类型为对方的属性。如教师Teacher端为控制关系的一方,则Teacher实体如下:
public class Teacher{
    @OneToOne(cascade|fetch|targetEntity) //每个选项可取值可查阅API
    @JoinColumn(name="student_no") //name指定外键列
    private Student student;
}
Teacher表中应该有一列student_no,Student实体不需要任何注解,也不包含类型为Teacher的属性。如果指定了相应的级联属性,则持久化Teacher时可同时持久化Student
  • 单向1-N:需要在控制关系的一方实体中使用注解@OneToMany、@JoinColumn标注类型为对方的集合属性。如教师Teacher端为控制关系的一方,则Teacher实体如下
public class Teacher{
    @OneToMany(cascade|fetch|targetEntity) //每个选项可取值可查阅API
    @JoinColumn(name="teacher_no") //name指定外键列,这里注意指定的是teacher_no,下面会说明
    private Set<Student> students = new HashSet<>();
}
Teacher表中不会有student_no,Student表中应该有teacher_no,因为Teacher是1的一端,即主表,JPA会自动为合适的数据表增加外键列。Student实体不需要任何注解,也不包含类型为Teacher的属性。如果指定了相应的级联属性,则持久化Teacher时可同时持久化Student
  • 单向N-1:需要在控制关系的一方实体中使用注解@ManyToOne、@JoinColumn标注类型为对方的属性。如教师Teacher端为控制关系的一方,则Teacher实体如下
public class Teacher{
    @ManyToOne(cascade|fetch|targetEntity) //每个选项可取值可查阅API
    @JoinColumn(name="student_no") //name指定外键列
    private Student student;
}
Teacher表中应该有一列student_no,Student实体不需要任何注解,也不包含类型为Teacher的属性。如果指定了相应的级联属性,则持久化Teacher时可同时持久化Student
  • 单向N-N:需要在控制关系的一方实体中使用注解@ManyToMany、@JoinTable标注类型为对方的属性,这里应该是一个集合属性。如教师Teacher端为控制关系的一方,则Teacher实体如下
public class Teacher{
    @ManyToMany(cascade|fetch|targetEntity) //每个选项可取值可查阅API
    @JoinTable(name="teacher_student",joinColumns=@JoinColumn(name="teacher_no"),inverseJoinColumns=@JoinColumn(name="student_no")) 
    //name指定连接表,也就是除Teacher和Student之外的第三个表,由它来维护关系。joinColumns指定当前实体的主键,inverseJoinColumns指定关联实体的主键
    private Set<Student> students = new HashSet<>();
}
teacher_student表中应该包含两列teacher_no和student_no,Student实体不需要任何注解,也不包含类型为Teacher的属性。如果指定了相应的级联属性,则持久化Teacher时可同时持久化Student
  • 双向1-1:双方均要包含类型为对方的集合属性,控制关系的一方需要使用注解@OneToOne、@JoinColumn标注类型为对方的属性,不控制关系的一方需要在@OneToOne中指定mappedBy选项。如教师Teacher端为控制关系的一方,则Teacher实体和Student实体如下
public class Teacher{
    @OneToOne(cascade|fetch|targetEntity) //每个选项可取值可查阅API
    @JoinColumn(name="student_no") //name指定外键列
    private Student student;
}

public class Student{
    @OneToOne(mappedBy="student",cascade|fetch|targetEntity) //mappedBy指明这端不控制关系,其他每个选项可取值可查阅API
    private Teacher teacher;
}
Teacher表中应该有一列student_no,Student表中不会有teacher_no。如果指定了相应的级联属性,则持久化Teacher时可同时持久化Student

- 双向1-N(N-1):1的一端需要使用注解@OneToMany标注类型为对方的集合属性,同时指定mappedBy属性表示1的一端不控制关系,N的一端则需要使用注解@ManyToOne、@JoinColumn标注类型为对方的属性。如学生Student端为控制关系的一方,则Teacher实体和Student实体如下

public class Teacher{
    @OneToMany(mappedBy="teacher",cascade|fetch|targetEntity) //mappedBy指明这端不控制关系,其他每个选项可取值可查阅API
    private Set<Student> students = new HashSet<>();
}

public class Student{
    @ManyToOne(cascade|fetch|targetEntity) //每个选项可取值可查阅API
    @JoinColumn(name="teacher_no") //name指定外键列
    private Teacher teacher;
}
Student表中应该有一列teacher_no,如果指定了相应的级联属性,则持久化Student时可同时持久化Tacher

- 双向N-N:双方均要包含类型为对方的集合属性,控制关系的一方需要使用注解@ManyToMany、@JoinTable标注类型为对方的集合属性,不控制关系的一方需要在@ManyToMany中指定mappedBy选项。如教师Teacher端为控制关系的一方,则Teacher实体和Student实体如下

public class Teacher{
    @ManyToMany(cascade|fetch|targetEntity) //每个选项可取值可查阅API
    @JoinTable(name="teacher_student",joinColumns=@JoinColumn(name="teacher_no"),inverseJoinColumns=@JoinColumn(name="student_no")) 
    //name指定连接表,也就是除Teacher和Student之外的第三个表,由它来维护关系。joinColumns指定当前实体的主键,inverseJoinColumns指定关联实体的主键
    private Set<Student> students = new HashSet<>();
}

public class Student{
    @ManyToMany(mappedBy="students",cascade|fetch|targetEntity) //mappedBy指明这端不控制关系,其他每个选项可取值可查阅API
    private Set<Teacher> teachers = new HashSet<>();
}
teacher_student表中应该包含两列teacher_no和student_no,如果指定了相应的级联属性,则持久化Teacher时可同时持久化Student

最后,建议尽量显示指定targetEntity,第一可避免包含集合属性时未加泛型信息而出错;第二可以提升性能,因为默认情况下JPA会通过反射判断关联实体的类型。

JavaEE API文档:http://docs.oracle.com/javaee/7/api/