在我们做数据库设计的时候,最烦的就是各种表之间的关联关系了,关联关系有:一对多,多对一,一对一,其中还有单向和双向的区别.

  1.双向一对多及多对一映射:既然是双向,那么就是同一类的了:双向一对多关系中,必须存在一个关系维护端,在 JPA 规范中,要求 many 的一方作为关系的维护端(owner side), one 的一方作为被维护端(inverse side)。 可以在 one 方指定 @OneToMany 注释并设置 mappedBy 属性,以指定它是这一关联中的被维护端,many 为维护端。 在 many 方指定 @ManyToOne 注释,并使用 @JoinColumn 指定外键名称,讲的比较难理解,下面是代码:

  

User.java:  
@OrderBy("id")//指的是取出数据的时候,按照哪一个字段来进行排列,我们这里是按照user表的id字段排序,默认是ASC,完整用法:@OrderBy(value= "group_name ASC, name DESC")   
@OneToMany(targetEntity=Phone.class,mappedBy="user")//mappedBy说的就是上面说的被维护端,多的那一端就是维护端,注意mappedBy="xxx" xxx表示的是在另外一个类中关联这个类的那个属性名,在这个例子中是user(需要注意,这里必须是相同的名称,如果不同的话,是会报错的)
public Set<Phone> getPhones() {
return phones;
}
Phone.java
  @JoinColumn(name="user_id")//指定在本实体所映射的那个表中关联的外键
@ManyToOne(targetEntity=User.class)//
public User getUser() {
return user;
}

顺带讲一下,单向多对一的怎么做,对于上面的代码来说,我们只要将User中将被维护的注解给去掉,当然Set<Phone>也需要去掉。

下面再讲一下单向一对多:

JPA单向一对多只需要在多的一端使用如下注解:

@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)//级联保存、更新、删除、刷新;延迟加载36  
@JoinColumn(name="author_id")//在book表增加一个外键列来实现一对多的单向关联
private Set<Book> books = new HashSet<Book>();

而在Book.java里头不需要任何有关author的信息。

但是经过测试发现,在Book表中,author_id需要设置允许为空,因为JPA是先往两张表插入新数据,然后再更新Book表中的author_id字段的。

所以不可以在数据库中设置该外键为空。

推荐使用双向关系

2.双向一对一映射:基于外键的 1-1 关联关系:在双向的一对一关联中,需要在关系被维护端(inverse side)中的 @OneToOne 注释中指定 mappedBy,以指定是这一关联中的被维护端。同时需要在关系维护端(owner side)建立外键列指向关系被维护端的主键列。
  

User.java:   
@OneToOne(mappedBy="user")//因为需要指定其中一方为被维护段,我们设置user为被维护段,和双向一对多相同,这个名称必须和FirstLover定义User属性的名称一样
public FirstLover getFirstLover() {
return firstLover;
}
FirstLover.java:
//使用OneToOne进行一对一的映射,name表示的是关联关系表的外键,注意的是,这个外键是被维护段的主键,所以是unqie的
@JoinColumn(unique=true,name="user_id")
@OneToOne
public User getUser() {
return user;
}

在关联关系中,延迟加载经常是我们考虑的问题,可以使用在我们的这个例子中,可以使用:

    @JoinColumn(unique=true,name="user_id")
@OneToOne(fetch=FetchType.LAZY)
public User getUser() {
return user;
}

但是,有这样的情况:user可以不关联firstLover(因为外键是定义在FirstLover表中的),如果有 FirsetLover 关联就设置为代理对象而延迟加载, 如果不存在关联的 FirsetLover 就设置 null, Hibernate 在不读取 FirsetLover  表的情况是无法判断是否有关联有 FirsetLover , 因此无法判断设置 null 还是代理对象, 而统一设置为代理对象,也无法满足不关联的情况, 所以无法使用延迟加载,只 有显式读取 FirsetLover .

单向一对一的话只需要在上面增加注解就可以了

    @OneToOne(fetch=FetchType.EAGER)
protected User updateUser;//这样就是将user的id作为我们现在这个注解了的表的外键了。这样子就单向的关联上了

最后一种就是多对多的关联关系的情况,在双向多对多关系中,我们必须指定一个关系维护端(owner side),可以通过 @ManyToMany 注释中指定 mappedBy 属性来标识其为关系维护端。为了测试,我定义了两个类:

Student.java:
package com.hotusm.commom.entity; import java.util.HashSet;
import java.util.Set; import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany; @Entity
public class Student { private Integer id; private String name;
private String sex; private String school;
private Set<Teacher> teachers=new HashSet<>(); @GeneratedValue
@Id
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
} @JoinTable(name="teach_stu",//指定中间表的表名,如果没有指定表名,那么默认的名字是:tab1_tab2
joinColumns={@JoinColumn(name="teacher_id",//指定本类的主键在中间表的外键的字段名称,
referencedColumnName="ID")},//指定本类的主键是什么,在这个例子中,teach_stu的teacher的id就是本类的主键值
inverseJoinColumns={@JoinColumn(name="student_id",//和上面是一样的含义,指明另外一个类主键在中间表的名称
referencedColumnName="ID" //指定另外一个类的主键是什么,这里都是ID
)}
)
@ManyToMany//加上多对多的标示
public Set<Teacher> getTeachers() {
return teachers;
}
public void setTeachers(Set<Teacher> teachers) {
this.teachers = teachers;
}
@Override
public String toString() {
return this.name;
}
}
Teacher:
package com.hotusm.commom.entity; import java.util.HashSet;
import java.util.Set; import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany; @Entity
public class Teacher { private Integer id; private String name; private String subjectName; private Set<Student> students=new HashSet<>(); @GeneratedValue
@Id
public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Column(name="SUBJECT_NAME")
public String getSubjectName() {
return subjectName;
}
public void setSubjectName(String subjectName) {
this.subjectName = subjectName;
} @ManyToMany(mappedBy="teachers")//指定维护的一方,注意这里的名称是另外一个类的属性名: private Set<Teacher> teachers=new HashSet<>();
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
@Override
public String toString() { return this.name;
}
}

基本上,关联关系也就几种了。

最新文章

  1. JSTL标签 参考手册
  2. 准备上线,切换到master分支,报错
  3. 在Mac上安装Sublime Text3的插件
  4. brew gradle
  5. 移除IIS默认的响应头(转载)
  6. ThinkPHP去重 distinct和group by
  7. 双向循环链表的Java版本实现
  8. GitHub上排名前100的iOS开源库介绍(来自github)
  9. Android优化—— 内存分析工具 MAT 的使用
  10. 响应式web设计读书笔记
  11. 李洪强iOS开发之零基础学习iOS开发】【02-C语言】01-概述
  12. UVa 10256 (判断两个凸包相离) The Great Divide
  13. UVa657 The die is cast
  14. (转)你知道Android也有安全模式吗?(地球人都知道了吧)
  15. ZTESoft 持续集成 编年史 之 持续集成探索---平台选择
  16. HDU2048 HDU2049 组合数系列 错排
  17. Android 调用 .NET WebService
  18. ActiveMQ的安装与使用(单节点)
  19. 芯灵思Sinlinx A64开发板Linux内核定时器编程
  20. windows server 2012 远程桌面不好使

热门文章

  1. C++14 make code cleaner
  2. mac或linux下xampp的mysql配置
  3. IBM HTTP Server Performance Tuning
  4. 深圳测试研讨会圆满结束,PPT共享
  5. wordpress使用技巧
  6. 8个经典HTML5 3D动画赏析
  7. 图解 &amp; 深入浅出JavaWeb:事务必会必知
  8. 玩转MAC OS!实测DIY兼容机装苹果系统
  9. MySQL Cluster 集群
  10. unix/linux中图形界面那些事