- 注:这是笔者在学习过程的小小知识记录,可能有错误的地方,仅供参考
JPA的表映射关系
在JPA同样也有一对多,多对多等的多表关系,因为没有了映射文件,因此持久化类与持久化类之间的关系也是由注解来进行定义。
一对多关系
- 持久化类的代码示例
- Company类(一的一方)
package com.wzm.entity;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
/*
* Entity表明这是一个持久化类
* Table表明这个类所对应的表,name为数据库的表名
*/
@Entity
@Table(name="company")
public class Company {
/*
* Id表明这是持久化类的OID
* Column表明该属性所对应的表字段,name为表字段名
* @GeneratedValue:定义OID的自增长方式
*/
@Id
@Column(name="cid")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long cid;
@Column(name="cname")
private String cname;
/*
* 公司可以有很多员工,因此公司属于一的一方,在一的一方要有多的一方的对象集合Set<Employee> employees
* @OneToMany表明这是一个一对多的关系,并且这是一的一方
* targetEntity为对方的Class对象
* mappedBy表明自己这方被对方的哪个属性所映射,注意该属性不能与注解joinColumn和joinTable共存,否则会报错
* 在多的一方会有一的一方的对象,这里就填对方所定义的对象的属性名
* 注意,这个属性只在onetomany中有,也就是只在一的一方有
* mappedBy属性一般都要加上,否则本方不会认同对方创建的外键,会自己再创建出一个中间表
* 属性:cascade定义级联操作,PERSIST保存,MERGE级联更新,REMOVE级联删除,ALL级联所以操作
* fetch:定义加载方式,EAGER立即加载,LAZY延迟加载
*/
@OneToMany(targetEntity=Employee.class,mappedBy="company",cascade=CascadeType.PERSIST,fetch=FetchType.LAZY)
private Set<Employee> employees = new HashSet<>();
//省略getter和setter
}
- Employee类(多的一方)
package com.wzm.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
/*
* Entity表明这是一个持久化类
* Table表明这个类所对应的表,name为数据库的表名
*/
@Entity
@Table(name="employee")
public class Employee {
/*
* Id表明这是持久化类的OID
* Column表明该属性所对应的表字段,name为表字段名
* @GeneratedValue:定义OID的自增长方式
*/
@Id
@Column(name="eid")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long eid;
@Column(name="ename")
private String ename;
/*
* 很多员工都属于同一家公司,员工属于多的一方,在多的一方要有一的一方的对象Company company,这个属性名在一的一方的mappeBy会用到
* @ManyToOne表明这是一对多关系,同时这属于多的一方
* targetEntity为对方的class对象
* 在多的一方所对应的数据库的表中,一般都有一个外键指向一的一方
* @JoinColumn这表明往表中添加一个外键,name为外键的字段名,注意该注解不能与属性mappedBy共存,否则会报错
* 因为外键一般指向一个对应的主键,referencedColumnName就是填所对应的主键,
* 这里外键指向一的一方的主键,填的就是一的一方所对应表的主键字段名
*/
@ManyToOne(targetEntity=Company.class)
@JoinColumn(name="cid",referencedColumnName="cid")
private Company company;
//省略getter和setter
}
- 一对多关系的基本操作
@Test
public void test3() {
//创建一个实体管理工厂,EntityManagerFactory类似于SessionFactory,
//传入的参数要与persistence.xml中的persistence-unit的name属性一致
//类似于加载配置文件
EntityManagerFactory emf = Persistence.createEntityManagerFactory("mysql");
//获取实体管理对象,类似hibernate的session对象
EntityManager em = emf.createEntityManager();
//获取事务对象,在JPA中同样也要启用事务
EntityTransaction transaction = em.getTransaction();
//开启事务
transaction.begin();
//创建一个公司对象和两个员工对象
Company company = new Company();
company.setCname("byte");
Employee e1 = new Employee();
e1.setEname("xiaoming");
Employee e2 = new Employee();
e2.setEname("daming");
//关联对象之间的关系
company.getEmployees().add(e1);
company.getEmployees().add(e2);
e1.setCompany(company);
e2.setCompany(company);
//保存对象,这里如果只单独保存公司对象不会像hibernate会报错,因为在hibernate双方默认会维护外键,
//在JPA中,正常配置的话,一的一方默认是不会维护外键的
//其他的基本操作都与hibernate类似
em.persist(company);
em.persist(e1);
em.persist(e2);
//提交事务
transaction.commit();
//关闭资源
em.close();
emf.close();
}
- 一对多关系的级联操作
@Test
public void test4() {
//创建一个实体管理工厂,EntityManagerFactory类似于SessionFactory,
//传入的参数要与persistence.xml中的persistence-unit的name属性一致
//类似于加载配置文件
EntityManagerFactory emf = Persistence.createEntityManagerFactory("mysql");
//获取实体管理对象,类似hibernate的session对象
EntityManager em = emf.createEntityManager();
//获取事务对象,在JPA中同样也要启用事务
EntityTransaction transaction = em.getTransaction();
//开启事务
transaction.begin();
//创建一个公司对象和两个员工对象
Company company = new Company();
company.setCname("byte");
Employee e1 = new Employee();
e1.setEname("xiaoming");
Employee e2 = new Employee();
e2.setEname("daming");
//关联对象之间的关系
company.getEmployees().add(e1);
company.getEmployees().add(e2);
e1.setCompany(company);
e2.setCompany(company);
//因为每次保存公司还保存员工太繁琐,因此可以使用级联在保存公司时自动保存关联的员工
//在一的一方的@OneToMany添加属性cascade=CascadeType.PERSIST,就可以级联保存
//JPA也可以双向级联操作
//级联操作都与hibernate类似,注意避免使用级联删除
em.persist(company);
//提交事务
transaction.commit();
//关闭资源
em.close();
emf.close();
}
多对多关系
- 持久化类的代码示例
- Student类(放弃外键维护的一方)
package com.wzm.entity;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
/*
* Entity表明这是一个持久化类
* Table表明这个类所对应的表,name为数据库的表名
*/
@Entity
@Table(name="student")
public class Student {
/*
* Id表明这是持久化类的OID
* Column表明该属性所对应的表字段,name为表字段名
* @GeneratedValue:定义OID的自增长方式
*/
@Id
@Column(name="sid")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long sid;
@Column(name="sname")
private String sname;
/*
* 在多对多的关系中,双方都要有对方的对象集合
* @ManyToMany表明这是多对多的关系,targetEntity为对方的class对象,mappedBy为对方所定义的本方对象集合的属性名
* 注意:mappedBy不能与注解@JoinColumn和@JoinTabe共存
* 使用mappedBy相当于放弃外键的维护,直接由对方支配,
* 在多对多关系中双方不能同时有JoinTable注解,否则会报错,
* 同时没有jointable注解的一方要有mappedBy属性,否则本方不会认同对方创建的中间表,会自己再创建的中间表
*
* 属性:cascade定义级联操作,PERSIST保存,MERGE级联更新,REMOVE级联删除,ALL级联所以操作
* fetch:定义加载方式,EAGER立即加载,LAZY延迟加载
*/
@ManyToMany(targetEntity=Teacher.class,mappedBy="students",cascade=CascadeType.PERSIST,fetch=FetchType.LAZY)
private Set<Teacher> teachers = new HashSet<>();
//省略getter和setter
}
- Teacher类(维护外键的一方)
package com.wzm.entity;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
@Entity
@Table(name="teacher")
public class Teacher {
/*
* Id表明这是持久化类的OID
* Column表明该属性所对应的表字段,name为表字段名
* @GeneratedValue:定义OID的自增长方式
*/
@Id
@Column(name="tid")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long tid;
@Column(name="tname")
private String tname;
/*
* 在多对多的关系中,双方都要有对方的对象集合
* @ManyToMany表明这是多对多的关系,targetEntity为对方的class对象
* 因为在多对多的关系中,一般都需要一个中间表,
* @JoinTable就是往数据库中加入中间表,属性name为中间表的表名,注意该注解不能与属性mappedBy共存,否则会报错
* 在中间表中一般有两个外键分别指向两张表,
* 属性joinColumns就是就是往中间表加入一个外键指向本方,
* 在属性中又定义一个注解@JoinColumn,注解中属性name为中间表指向本方的外键字段名,referencedColumnName就是本方对应表的主键字段名
* 属性inverseJoinColumns就是往中间表加入外键指向对方
* 在属性中又定义一个注解@JoinColumn,注解中属性name为中间表指向对方的外键字段名,referencedColumnName就是对方对应表的主键字段名
* JoinTable在哪一方都可以,只是没有该注解的另一方就要有mappedBy属性
*
* 属性:cascade定义级联操作,PERSIST保存,MERGE级联更新,REMOVE级联删除,ALL级联所以操作
* fetch:定义加载方式,EAGER立即加载,LAZY延迟加载
*/
@ManyToMany(targetEntity=Student.class,cascade=CascadeType.PERSIST,fetch=FetchType.LAZY)
@JoinTable(name="stu_tea_tab",
joinColumns= {
@JoinColumn(name="tid",referencedColumnName="tid")
},inverseJoinColumns= {
@JoinColumn(name="sid",referencedColumnName="sid")
})
private Set<Student> students = new HashSet<>();
//省略getter和setter
}
- 多对多关系的基本操作
@Test
public void test5() {
//创建一个实体管理工厂,EntityManagerFactory类似于SessionFactory,
//传入的参数要与persistence.xml中的persistence-unit的name属性一致
//类似于加载配置文件
EntityManagerFactory emf = Persistence.createEntityManagerFactory("mysql");
//获取实体管理对象,类似hibernate的session对象
EntityManager em = emf.createEntityManager();
//获取事务对象,在JPA中同样也要启用事务
EntityTransaction transaction = em.getTransaction();
//开启事务
transaction.begin();
//创建两个学生对象和两个老师对象
Teacher t1 = new Teacher();
t1.setTname("t1");
Teacher t2 = new Teacher();
t2.setTname("t2");
Student s1 = new Student();
s1.setSname("s1");
Student s2 = new Student();
s2.setSname("s2");
//关联对象之间的关系
t1.getStudents().add(s1);
t1.getStudents().add(s2);
t2.getStudents().add(s2);
s1.getTeachers().add(t1);
s2.getTeachers().add(t1);
s2.getTeachers().add(t2);
//保存对象,其他的基本操作都与hibernate类似
em.persist(t1);
em.persist(t2);
em.persist(s1);
em.persist(s2);
//提交事务
transaction.commit();
//关闭资源
em.close();
emf.close();
}
- 多对多关系的级联操作
@Test
public void test6() {
//创建一个实体管理工厂,EntityManagerFactory类似于SessionFactory,
//传入的参数要与persistence.xml中的persistence-unit的name属性一致
//类似于加载配置文件
EntityManagerFactory emf = Persistence.createEntityManagerFactory("mysql");
//获取实体管理对象,类似hibernate的session对象
EntityManager em = emf.createEntityManager();
//获取事务对象,在JPA中同样也要启用事务
EntityTransaction transaction = em.getTransaction();
//开启事务
transaction.begin();
//创建两个学生对象和两个老师对象
Teacher t1 = new Teacher();
t1.setTname("t1");
Teacher t2 = new Teacher();
t2.setTname("t2");
Student s1 = new Student();
s1.setSname("s1");
Student s2 = new Student();
s2.setSname("s2");
//关联对象之间的关系
t1.getStudents().add(s1);
t1.getStudents().add(s2);
t2.getStudents().add(s2);
s1.getTeachers().add(t1);
s2.getTeachers().add(t1);
s2.getTeachers().add(t2);
//同样JPA的多对多也支持级联操作,@ManyToMany添加属性cascade=CascadeType.PERSIST,就可以级联保存
//JPA也可以双向级联操作
//多对多一般不使用级联操作,还要避免使用级联删除
//级联保存,其他操作和hibernate类似
em.persist(t1);
em.persist(t2);
//提交事务
transaction.commit();
//关闭资源
em.close();
emf.close();
}