JPA实体映射——多对一关系映射

百科知识2025-04-262

前几节我们介绍了一对多的关系和一对一关系,今天我们学习多对一关系以及这种映射方式的最佳实践,先上业务实例图。

在我们的业务关系图中,部门和研究所实体是多对一的关系,同时我们还是采用双向关联来说明问题

###Bidirectional @ManyToOne ###部门实体 import javax.persistence.*; import java.io.Serializable; import java.util.Objects; @Entity(name = "Department") @Table(name = "departments") public class Department implements Serializable { @Id @GeneratedValue private Long id = 0L; private String name; @ManyToOne(fetch = FetchType.LAZY) private Institute institute; public Department(){} public void setId(Long id) { this.id = id; } public void setName(String name) { this.name = name; } public void setInstitute(Institute institute) { this.institute = institute; } public Department(String name){ this.name = name; } public Long getId() { return id; } public String getName() { return name; } public Institute getInstitute() { return institute; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Department)) return false; Department that = (Department) o; return name.equals(that.name); } @Override public int hashCode() { return Objects.hash(name); } } ###DepartmentDAO import com.jpa.demo.model.bidirectional.Department; import com.jpa.demo.model.bidirectional.Institute; import com.jpa.demo.utils.JPAUtil; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; public class DepartmentDAO { private EntityManagerFactory entityManagerFactory = JPAUtil.getEntityManagerFactory(); public void saveDepartment(Long instituteId) { EntityManager entityManager = null; Long id = null; try { entityManager = this.entityManagerFactory.createEntityManager(); EntityTransaction tx = entityManager.getTransaction(); tx.begin(); Institute institute = entityManager.find(Institute.class, instituteId); Department department = new Department("深圳研究所-第一部门"); department.setInstitute(institute); entityManager.persist(department); tx.commit(); } finally { entityManager.close(); } } } ###测试代码 @Test public void testSaveDepartment() { Institute institute = new Institute("深圳研究所"); institute.addDepartment( new Department("深圳研究所1部") ); InstituteDAO dao = new InstituteDAO(); dao.save(institute); Long instituteId = institute.getId(); DepartmentDAO departmentDAO = new DepartmentDAO(); departmentDAO.saveDepartment(instituteId); } ###日志信息 Hibernate: select institute0_.id as id1_1_0_, institute0_.name as name2_1_0_ from institutes institute0_ where institute0_.id=? Hibernate: call next value for hibernate_sequence Hibernate: insert into departments (institute_id, name, id) values (?, ?, ?)

可以看出,我在保存部门信息的时候,同时还查询除了研究所信息,这里可以优化为直接保存部门信息。

只需要修改一行代码

Institute institute = entityManager.getReference(Institute.class, instituteId);

修改成getReference()方法后,就不用去查询研究所的实体啦。

Hibernate: insert into departments (institute_id, name, id) values (?, ?, ?)

 

查询多对一多方的一条记录,查询方法如下:

public void queryDepartment(Long departmentId) { EntityManager entityManager = null; try { entityManager = this.entityManagerFactory.createEntityManager(); EntityTransaction tx = entityManager.getTransaction(); tx.begin(); Department department = entityManager.find(Department.class, departmentId); department.getInstitute().getName(); tx.commit(); } finally { entityManager.close(); } } ###测试代码 @Test public void testQueryDepartment() { Institute institute = new Institute("深圳研究所"); institute.addDepartment( new Department("深圳研究所1部") ); InstituteDAO dao = new InstituteDAO(); dao.save(institute); Long instituteId = institute.getId(); DepartmentDAO departmentDAO = new DepartmentDAO(); Department department = departmentDAO.saveDepartment(instituteId); Long departmentId = department.getId(); departmentDAO.queryDepartment(departmentId); }

日志信息:

Hibernate: select department0_.id as id1_0_0_, department0_.institute_id as institut3_0_0_, department0_.name as name2_0_0_ from departments department0_ where department0_.id=? Hibernate: select institute0_.id as id1_1_0_, institute0_.name as name2_1_0_ from institutes institute0_ where institute0_.id=?

可以看出,为了获取研究所的信息,同时也查询了研究所实体,在此情况下,可以使用另一种方法不用查询研究所实体。

ublic void queryDepartmentByJPQL(Long departmentId) { EntityManager entityManager = null; try { entityManager = this.entityManagerFactory.createEntityManager(); EntityTransaction tx = entityManager.getTransaction(); tx.begin(); Department department = entityManager.createQuery("select dt from Department dt join fetch\n" + " dt.institute where dt.id =:id", Department.class) .setParameter("id",departmentId) .getSingleResult();; department.getInstitute().getName(); entityManager.persist(department); tx.commit(); } finally { entityManager.close(); } }

测试方法只需要修改一行

departmentDAO.queryDepartmentByJPQL(departmentId);

日志信息如下:

Hibernate: select department0_.id as id1_0_0_, institute1_.id as id1_1_1_, department0_.institute_id as institut3_0_0_, department0_.name as name2_0_0_, institute1_.name as name2_1_1_ from departments department0_ inner join institutes institute1_ on department0_.institute_id=institute1_.id where department0_.id=?

可以看出,这次只发出了一条SQL,不同于上一种方式发出了两条SQL,优化了性能,同时也取得了相应的值。