JPA(4)表表关联关系
在我们做数据库设计的时候,最烦的就是各种表之间的关联关系了,关联关系有:一对多,多对一,一对一,其中还有单向和双向的区别.
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;
}
}
基本上,关联关系也就几种了。
JPA(4)表表关联关系的更多相关文章
- Hibernate+JPA (EntityMange讲解)
近年来ORM(Object-Relational Mapping)对象关系映射,即实体对象和数据库表的映射)技术市场人声音鼎沸,异常热闹, Sun在充分吸收现有的优秀ORM框架设计思想的基础上,制定了 ...
- Hibernate+JPA
参考链接:http://blog.163.com/hero_213/blog/static/398912142010312024809 近年来ORM(Object-Relational Mapping ...
- Hibernate与Jpa的关系(2)
[转自:http://blog.163.com/hero_213/blog/static/398912142010312024809/ ] 近年来ORM(Object-Relational Mappi ...
- JPA + SpringData 操作数据库原来可以这么简单 ---- 深入了解 JPA - 2
原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7704914.html ------------------------------------ ...
- 深入了解 JPA
转载自:http://www.cnblogs.com/crawl/p/7703679.html 前言:谈起操作数据库,大致可以分为几个阶段:首先是 JDBC 阶段,初学 JDBC 可能会使用原生的 J ...
- JPA 映射单向多对一的关联关系
1.首先在多的一端加入一的一端的实体类 //映射单向n-1的关联关 //使用@ManyToOne 来映射多对一的关系 //使用@JoinColumn 来映射外键/可以使用@ManyToOne的fetc ...
- JPA学习笔记(8)——映射双向一对多关联关系
双向一对多关联关系 前面的博客讲的都是单向的,而本问讲的是双向的(双向一对多 = 双向多对一) 什么是双向? 我们来对照一下单向和双向 单向/双向 User实体类中是否有List< Order& ...
- JPA 单向一对多关联关系
映射单向一对多的关联关系 1.首先在一的一端加入多的一端的实体类集合 2.使用@OneToMany 来映射一对多的关联关系3.使用@JoinColumn 来映射外键列的名称4.可以使用@OneToMa ...
- Hibernate JPA 关联关系
Hibernate JPA 关联关系: 使用cascade做级联操作(只有在满足数据库约束时才会生效): CascadeType.PERSIST: 级联保存,只有调用persist()方法,才会级联保 ...
随机推荐
- text .global_start 和_start
.text定义一个代码段,这是GCC必须的.global_start和_start代码开始地址定义个标记
- Nginx upstream 长连接
原文: http://bollaxu.iteye.com/blog/900424 Nginx upstream目前只有短连接,通过HTTP/1.0向后端发起连接,并把请求的"Connecti ...
- truncate/drop表非常慢,怎么办?用硬链接,极速体验
这个这个,我必须花巨大篇幅,记录下今天清空表记录的英雄壮举,可知道一个drop操作,执行了一下午啊一下午,这是要急出翔的节奏..呵呵,下面开始 我的需求:某表因历史原因,积压了1亿条记录,约占360G ...
- Android开源代码分享
一.AppMsg实现自定义Toast. github下载地址 二.CircleImageView实现带边框圆形头像. github下载地址 ...
- Fast 迅捷网络 无线路由器FW323的功能设置
一.问题的提出 1.有一个无线路由器,型号:Fast 迅捷网络 无线路由器FW323 2.有三个网络层级,第一级,用一个路由器A负责对接互联网,内网IP段为192.168.1.*,网关设置192.16 ...
- myeclipse 2013 SR2 for(MAC/WINDOWS)破解 注册过程
前天去官网下载的时候都还只是sr1,结果昨天去看居然有sr2了,之前一直在windows下用 2013,网上的注册机都还很好用.但最近换了mac,下载的sr1我却无论如何都没办法破解,下载了N个版本的 ...
- Turtle Online:致力于打造超接地气的PC前端架构,组件+API,快速搭建前端开发
架构创作初衷 每当新开一个项目时,都会绞尽脑汁去考虑采用哪种框架:requirejs/seajs.jquery/zepto.backbone.easeUI/Bootstrap/AngularJS……, ...
- MFC设置静态文本框,编辑框等控件背景和字体颜色
在MFC类库提供了CWnd::OnCtlColor函数,在工作框架的子窗口被重画时将调用该成员函数.因此可以重载WM_CTLCOLOR消息的响应函数.此函数的原型:afx_msg HBRUSH OnC ...
- 自己动手搭建 CAS(Central Authentication Service) 环境,为了单点登录(Single Sign On , 简称 SSO )
介绍 刚刚搭建 CAS 成功了,现在记录下来,怕以后忘记,同时也给需要帮助的人.CAS 搭建需要服务端和客户端,服务端是 Java 写的,如果自己搭建则需要安装与配置 Java 环境.客户端可以是多种 ...
- 使用log4net
原文:<使用log4net,没有日志文件生成> Posted on 2014/06/12 ================================================= ...