JPA中映射关系详细说明(一对多,多对一,一对一、多对多)、@JoinColumn、mappedBy说明
JPA中的映射关系
jpa中维护one to one ,one to many, many to one ,many to many 四种映射关系。
在每个关系中,双方中的一方在其表中拥有连接列。那么一方称为所有方(owning side) 或者关系的所有者。
不具有连接列的一方称之为非所有方(non-owning)或者反方
所有权对于映射很重要,因为用于定义映射到数据库序列的物理注解(例如,@JoinColumn总是在关系的所有方定义)。如果它们不存在,那么值的默认值将从所有方的特性的角度来考虑。
多对一映射总是在关系的所有方之上,所以如果在拥有多对一方的关系中发现一个@JoinColumn,那么这将是所有方的位置。
注解@JoinColumn,需要指定连接列的名称,可以使用name元素。
举个例子来说: 学生和课程的关系定为一对多,
外键维护在多的一方,此时课程表映射的实体就是owning-side,学生表就是inverse-side
课程表
学生表
关系映射的使用到的注解说明
@JoinColumn
标记一个列指定实体的关联关系的。可以和@OneToMany或者@ManyToOne搭配使用
@OneToMany
在一的一方定义一对多的关联关系,并且如果关联关系时双向的,mappedBy属性必须用来标注,在拥有关联关系的实体一方中表示关系的字段名,也就是使用mappedBy属性是不维护关联关系的一方,值是拥有关联关系一方中标识关系的字段名
使用了mappedBy属性后,不能在使用@JoinColumn注解,会抛异常
@ManyToOne 没有mappedBy属性.
@OneToOne /@ManyToMany
都是在实体的字段上表示对应的关联关系,在表示双向关联关系时候,都必须使用mappedBy属性
单向多对一映射
成员和班级是多对一映射,并且外键列定义在成员表中,那么创建成员实体的时候,需要使用@JoinColumn标注
成员是关系的拥有者。也就是关系为多的一方持有
@JoinColumn的值是数据库中的外键名称,@JoinColumn和@ManyToOne搭配维护了关联关系,此时是单向的关联
Partner实体类
-
@Entity
-
@Table(name="partner_info")
-
public class Partner {
-
private Integer partner_id;
-
private String partner_name;
-
private Grade grade;
-
@Id
-
@Column(name="partner_id")
-
@GeneratedValue(strategy=GenerationType.IDENTITY)
-
public Integer getPartner_id() {
-
return partner_id;
-
}
-
public void setPartner_id(Integer partner_id) {
-
this.partner_id = partner_id;
-
}
-
@Column(name="partner_name")
-
public String getPartner_name() {
-
return partner_name;
-
}
-
public void setPartner_name(String partner_name) {
-
this.partner_name = partner_name;
-
}
-
@JoinColumn(name="team_id")
-
@ManyToOne
-
public Grade getGrade() {
-
return grade;
-
}
-
public void setGrade(Grade grade) {
-
this.grade = grade;
-
}
-
}
Grade实体类
-
@Entity
-
@Table(name="grade_info")
-
public class Grade {
-
private Integer teamId;
-
private String teamName;
-
@Id
-
@Column(name="team_id")
-
@GeneratedValue(strategy=GenerationType.IDENTITY)
-
public Integer getTeamId() {
-
return teamId;
-
}
-
public void setTeamId(Integer teamId) {
-
this.teamId = teamId;
-
}
-
@Column(name="team_name",columnDefinition="varchar(50) not null ")
-
public String getTeamName() {
-
return teamName;
-
}
-
public void setTeamName(String teamName) {
-
this.teamName = teamName;
-
}
-
}
测试下:
-
public static void main(String[] args) {
-
EntityManagerFactory factory = Persistence.createEntityManagerFactory("jpa");
-
EntityManager entityManager = factory.createEntityManager();
-
EntityTransaction transaction = entityManager.getTransaction();
-
transaction.begin();
-
//执行insert操作
-
Grade grade = new Grade();
-
grade.setTeamName("初中1班");
-
-
Partner p1 = new Partner();
-
p1.setPartner_name("张三风");
-
-
Partner p2 = new Partner();
-
p2.setPartner_name("李四关");
-
-
p1.setGrade(grade);
-
p2.setGrade(grade);
-
-
entityManager.persist(grade);
-
entityManager.persist(p1);
-
entityManager.persist(p2);
-
transaction.commit();
-
entityManager.close();
-
factory.close();
-
}
在实体创建中,字段的定义和数据库表的字段类型、长度、是否非空一致,不一致容易出问题。
如果出现问题,可以试着将数据库的表删除,交给JPA自己创建,持久化的过程会自动创建表。JPA会自动建表和外键关系.
每一个建立的实体都是javaBean风格的。
数据库中原来不存在表partner_info和grade_info,通过JPA将会在数据库中将生成对应的表,并且生成外键关系
JPA自动建表的策略需要配置: hibernate.ddl-auto 属性
hibernate.ddl-auto节点的值有几个create、create-drop、update、validate、none
create:每次加载hibernate会自动创建表,以后启动会覆盖之前的表,所以这个值基本不用,严重会导致的数据的丢失。
create-drop : 每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除,下一次启动会重新创建。
update: 加载hibernate时根据实体类model创建数据库表,这是表名的依据是@Entity注解的值或者@Table注解的值,sessionFactory关闭表不会删除,且下一次启动会根据实体 model更新结构或者有新的实体类会创建新的表。
validate:启动时验证表的结构,不会创建表
none:启动时不做任何操作
表的字段字段类型可以使用@Column注解的columnDefinition 指定。
如果表创建失败,是映射表没有定义正确
,
持久化顺序,是先持久化一的一方,再去持久化多的一方,这样不会多执行update语句
单向一对一映射
员工Employee到停车位ParkingSpace的关系是一对一关系,一对一映射在一个数据库表中存在一个连接列(外键列),需要在拥有外键列的一方实体中使用@JoinColumn注解中指定列名,并使用@OneToOne注解标识映射关系
-
@Entity
-
@Table(name="employee")
-
public class Employee {
-
@Id
-
@Column(name="id")
-
@GeneratedValue(strategy=GenerationType.IDENTITY)
-
private Integer id;
-
@Column(name="name")
-
private String name;
-
@Column(name="salary",columnDefinition="DECIMAL(10,2)")
-
private BigDecimal salary;
-
@JoinColumn(name="pspace_id")
-
@OneToOne
-
private ParkingSpace ps;
-
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 BigDecimal getSalary() {
-
return salary;
-
}
-
public void setSalary(BigDecimal salary) {
-
this.salary = salary;
-
}
-
public ParkingSpace getPs() {
-
return ps;
-
}
-
public void setPs(ParkingSpace ps) {
-
this.ps = ps;
-
}
-
}
-
@Entity
-
@Table(name="parking_space")
-
public class ParkingSpace{
-
@Id
-
@Column(name="id")
-
@GeneratedValue(strategy=GenerationType.IDENTITY)
-
private Integer id;
-
@Column(name="lot")
-
private Integer lot;
-
@Column(name="location")
-
private String location;
-
public Integer getId() {
-
return id;
-
}
-
public void setId(Integer id) {
-
this.id = id;
-
}
-
public String getLocation() {
-
return location;
-
}
-
public void setLocation(String location) {
-
this.location = location;
-
}
-
public Integer getLot() {
-
return lot;
-
}
-
public void setLot(Integer lot) {
-
this.lot = lot;
-
}
-
}
双向一对一关系
现在员工已经指向停车位,只要停车位实体在指向员就构成双向的关系
首先,必须清楚包含连接列的一方,决定了是关系的所有者,可是在双向一对一关系中,两个映射均是一对一映射,两方
都可以是所有者,最后,关系的拥有者只能有一个,连接列只能在一方,另一方只能指向关系的拥有者
ParkingSpace实体,添加@OneToOne表示映射关系,并且添加mappBy元素表示关系的所有方是Employee。
ParkingSpace修改如下;
-
@Entity
-
@Table(name="parking_space")
-
public class ParkingSpace{
-
@Id
-
@Column(name="id")
-
@GeneratedValue(strategy=GenerationType.IDENTITY)
-
private Integer id;
-
@Column(name="lot")
-
private Integer lot;
-
@Column(name="location")
-
private String location;
-
@OneToOne(mappedBy="ps")
-
private Employee el;
-
public Employee getEl() {
-
return el;
-
}
-
public void setEl(Employee el) {
-
this.el = el;
-
}
-
...........
双向一对一关联的规则;
1. @JoinColumn注解只能放置在映射到包含连接列的表的实体上。
2. mappedBy元素应该在没有定义连接列的实体的@OneToOne注解中指定,就是没有持有关系的一方使用
3. 双向一对一映射关系中只能有一方使用mappedBy属性
集合值关联
当源实体引用一个或者多个目标实体实例时候,将使用一个多值关联(many-value association)或者关联集合。体现在一对多和多对多关联关系中
1. 一对多映射
员工Employee和部门Department的关系,如果使用一对多映射表示,本质上是双向的
一个关系是双向的,意味着存在两个映射关系。双向的一对多映射意味着一个回源的多对一映射。
当一个源实体中有任意数量的目标实体存储在它的集合属性中,没有可以扩展的方式可以用于在数据库表中存储这些
它所映射到的引用。如何在单行中存储任意数量的外键?这是行不通的,因此,必须让集合中的实体表能够指向会
源实体表的外键。因而一对多是双向的。
-
@Entity
-
@Table(name="department_info")
-
public class DepartmentInfo {
-
@Id
-
@Column(name="id")
-
@GeneratedValue(strategy=GenerationType.AUTO)
-
private Integer id;
-
@Column(name="name")
-
private String name;
-
@OneToMany(mappedBy="department")
-
private List<Employee> list = new ArrayList<Employee>();
-
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 List<Employee> getList() {
-
return list;
-
}
-
public void setList(List<Employee> list) {
-
this.list = list;
-
}
-
}
-
@Entity
-
@Table(name="employee")
-
public class Employee {
-
@Id
-
@Column(name="id")
-
@GeneratedValue(strategy=GenerationType.IDENTITY)
-
private Integer id;
-
@Column(name="name")
-
private String name;
-
@Column(name="salary",columnDefinition="DECIMAL(10,2)")
-
private BigDecimal salary;
-
@JoinColumn(name="department_id")
-
@ManyToOne
-
private DepartmentInfo department;
-
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 BigDecimal getSalary() {
-
return salary;
-
}
-
public void setSalary(BigDecimal salary) {
-
this.salary = salary;
-
}
-
public DepartmentInfo getDepartment() {
-
return department;
-
}
-
public void setDepartment(DepartmentInfo department) {
-
this.department = department;
-
}
-
}
持久化先持久化一的一方,并且从持有关系的一方设值。
-
DepartmentInfo di = new DepartmentInfo();
-
di.setName("java开发部2");
-
Employee e1 = new Employee();
-
e1.setName("张三1");
-
e1.setSalary(new BigDecimal(110));
-
Employee e2 = new Employee();
-
e2.setName("李四1");
-
e2.setSalary(new BigDecimal(200));
-
e1.setDepartment(di);
-
e2.setDepartment(di);
-
//di.getList().add(e1); 持久化,只能从拥有关系的一方设值
-
//di.getList().add(e2);
-
entityManager.persist(di);
-
entityManager.persist(e1);
-
entityManager.persist(e2);
关于部门实体,有几点需要注意
1. 使用明确类型的集合类来存储,如果并不指定存储的类型,就必须使用targetEntity指示指向的类的信息。
2. 定义双向一对多关系时候,必须记住多的一方是关系的所有方,必须在那一方定义连接列,一对多的映射是反方,必须使用mappedBy元素
多对多映射
多对多是双向的关系映射,关系双方都是多对多关系,并且双方均没有连接列,需要借助中间表。因为每一个双向关系都必须具有所有方和反方,必须两个实体中挑选一个作为关系的持有者,反方使用mappedBy属性指向持有关系的一方。
使用@ManyToMany在实体的集合属性上表示映射关系。
-
@Entity
-
@Table(name="employee")
-
public class Employee {
-
@Id
-
@Column(name="id")
-
@GeneratedValue(strategy=GenerationType.IDENTITY)
-
private Integer id;
-
@Column(name="name")
-
private String name;
-
@Column(name="salary",columnDefinition="DECIMAL(10,2)")
-
private BigDecimal salary;
-
@JoinTable(name="employee_project_inner",
-
//中间表product_id字段
-
joinColumns={@JoinColumn(name="employee_id",referencedColumnName="id")},
-
inverseJoinColumns={@JoinColumn(name="project_id",referencedColumnName="id")}
-
)
-
@ManyToMany
-
private List<ProjectInfo> projects = new ArrayList<ProjectInfo>();
-
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 BigDecimal getSalary() {
-
return salary;
-
}
-
public void setSalary(BigDecimal salary) {
-
this.salary = salary;
-
}
-
public List<ProjectInfo> getProjects() {
-
return projects;
-
}
-
public void setProjects(List<ProjectInfo> projects) {
-
this.projects = projects;
-
}
-
}
@JoinTable说明;
joinColumns元素描述关系所有方在中间表的连接列,inverseJoinColumns元素指定了反方在中间表的连接列。
反方,使用mappedBy属性指向关系拥有的一方。
-
@Entity
-
@Table(name="project_info")
-
public class ProjectInfo {
-
@Id
-
@Column(name="id")
-
@GeneratedValue(strategy=GenerationType.IDENTITY)
-
private Integer id;
-
@Column(name="name")
-
private String name;
-
@ManyToMany(mappedBy="projects")
-
private List<Employee> employees = new ArrayList<Employee>();
-
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;
-
}
-
}
单向集合映射
当一个实体到目标实体存在一对多映射,但是@OneToMany注解不包括mappedBy元素时,就认为它存在目标实体的单向关系,此时,两个实体都不存在连接列,是单向的映射关系
需要借助中间表,存储映射关系
,同样的当多对多关系中,一方没有映射到另一方时候,就是一个单向的关系,也要借助连接表。
唯一的区别是,只有两个实体类型中的一个会使用该表来加载器相关的实体,或者更新它已存储新增的实体关联
创建实体:
目标实体中不会存在集合特性,源实体的@OneToMany注解中不存在mappedBy属性,
就是phone中没有集合属性,employee中@OneToMany注解不用mappedBy属性
-
@Entity
-
@Table(name="employee")
-
public class Employee {
-
@Id
-
@Column(name="id")
-
@GeneratedValue(strategy=GenerationType.IDENTITY)
-
private Integer id;
-
@Column(name="name")
-
private String name;
-
@Column(name="salary",columnDefinition="DECIMAL(10,2)")
-
private BigDecimal salary;
-
@JoinTable(name="employee_phone_inner",
-
//中间表product_id字段
-
joinColumns={@JoinColumn(name="employee_id",referencedColumnName="id")},
-
inverseJoinColumns={@JoinColumn(name="phone_id",referencedColumnName="id")}
-
)
-
@OneToMany
-
private List<Phone> phones = new ArrayList<Phone>(); //.. 省略get/set方法
-
@Entity
-
@Table(name="phone")
-
public class Phone {
-
@Id
-
@Column(name="id")
-
@GeneratedValue(strategy=GenerationType.IDENTITY)
-
private Integer id;
-
@Column(name="name")
-
private String num;
-
public Integer getId() {
-
return id;
-
}
-
public void setId(Integer id) {
-
this.id = id;
-
}
-
public String getNum() {
-
return num;
-
}
-
public void setNum(String num) {
-
this.num = num;
-
}
-
}
原文地址:https://blog.csdn.net/Ditto_zhou/article/details/80770926
JPA中映射关系详细说明(一对多,多对一,一对一、多对多)、@JoinColumn、mappedBy说明的更多相关文章
- Spring boot data JPA数据库映射关系 : @OneToOne,@OneToMany,@ManyToMany
问题描述 在利用Spring boot data JPA进行表设计的时候,表对象之间经常存在各种映射关系,如何正确将理解的映射关系转化为代码中的映射关系是关键之处. 解决办法 概念理解 举例:在公司的 ...
- hibernate 中映射关系配置
多对多 : 外键维护权,一方放弃inverse="true",并且不放弃维护权的一方,加入 cascade="save-update":推荐方案 Student ...
- 对Jpa中Entity关系映射中mappedBy的理解
mappedBy 单向关系不需要设置该属性,双向关系必须设置,避免双方都建立外键字段数据库中1对多的关系,关联关系总是被多方维护的即外键建在多方,我们在单方对象的@OneToMany(mappedby ...
- Hibernate中的一对一映射关系
Hibernate中的一对一映射关系有两种实现方法(单向一对一,和双向一对一)(一对一关系:例如一个department只能有一个manager) 单向和双向有什么区别呢??例如若是单向一对一,比如在 ...
- JPA中实现双向多对多的关联关系(附代码下载)
场景 JPA入门简介与搭建HelloWorld(附代码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103473937 ...
- Hibernate关联映射关系
Hibernate关联映射关系 一.双向一对多关联映射关系:当类与类之间建立了关联,就可以方便的从一个对象导航到另一个或另一组与它关联的对象(一对多双向关联和多对一双向关联是完全一样的) 1.1创建实 ...
- Spring Boot 入门系列(二十八) JPA 的实体映射关系,一对一,一对多,多对多关系映射!
前面讲了Spring Boot 使用 JPA,实现JPA 的增.删.改.查的功能,同时也介绍了JPA的一些查询,自定义SQL查询等使用.JPA使用非常简单,功能非常强大的ORM框架,无需任何数据访问层 ...
- JPA总结——实体关系映射(一对多@OneToMany)
JPA总结——实体关系映射(一对多@OneToMany) 注意:本文出自“阿飞”的博客,如果要转载本文章,请与作者联系! 并注明来源: http://blog.sina.com.cn/s/blog_4 ...
- Hibernate中的映射关系(一对多)
在数据库中表和表之间的关系有几种,(一对一,一对多,多对多)一对一关系:可以选择任意一方插入外键(one-to-one:one-to-one<--->many-to-one[unique= ...
随机推荐
- 启动Windows PowerShell ISE
Windows Server 2008 R2 环境下,启动PoserShell ISE方法: 方法1:在cmd.exe控制台或运行框中,输入 powershell_ise.exe 执行即可. 方法2: ...
- Spring日期格式初始化
原文链接地址 一.初始化参数绑定[一种日期格式] 配置步骤: ①:在applicationcontext.xml中只需要配置一个包扫描器即可 1 2 <!-- 包扫描器 --> ...
- 关于java的arrays数组排序示例AJPFX的分享
Java API对Arrays类的说明是:此类包含用来操作数组(比如排序和搜索)的各种方法. 1.对基本数据类型的数组的排序 说明: (1)Arrays类中的sort()使用的是“经过调优的快速排序法 ...
- 移动设备访问使用百度js跳转
以下为代码,可放置在网站foot底部文件,或者haead顶部文件,建议将代码放在网站顶部,这样可以实现手机访问立即跳转! <script src="http://siteapp.bai ...
- Safari兼容之new Date()格式问题
safari浏览器: 故: Safari浏览器应该用‘2017/10/23’来代替‘2017-10-23’ 谷歌浏览器: 谷歌浏览器两种格式都支持
- iOS Programming Touch Events and UIResponder
iOS Programming Touch Events and UIResponder 1 Touch Events As a subclass of UIResponder, a UIView ...
- axis2客户端的几种调用方式
(1)使用RPC方式调用WebService // 使用RPC方式调用WebService RPCServiceClient serviceClient = new RPCServiceClient( ...
- 【C++】模板简述(四):模板为什么不支持分离编译?
上文简述了类模板相关功能,本文主要简述为什么模板不支持分离编译? 在C++中,为了一个项目的规范,我们通常把代码归为三类:声明文件.实现文件.测试文件. 比如,我要用C++实现一个链表,那么就会创建这 ...
- 3D旋转矩阵的推导过程
3D旋转矩阵的推导过程 包含平移的线性变换称作仿射变换,3D中的仿射变换不能用 3 x 3 矩阵表达,必须使用4 x 4矩阵. 一般来说,变换物体相当于以相反的量变换描述这个物体的坐标系.当有多个变换 ...
- iTOP-6818开发板-Android4.4系统下RFID射频模块测试例程
平台:迅为iTOP-6818开发板 系统:Android4.4版本 例程:RFID射频模块测试例程 rc522 驱动在 Android 系统的内核是默认集成的,用户可以在开发板上使用命令“ls /de ...