Hibernate学习笔记七(JPA多表映射)

    xiaoxiao2022-07-12  185

    注:这是笔者在学习过程的小小知识记录,可能有错误的地方,仅供参考

    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(); }
    最新回复(0)