JPA实体映射——多对一关系映射
前几节我们介绍了一对多的关系和一对一关系,今天我们学习多对一关系以及这种映射方式的最佳实践,先上业务实例图。
<figure class="image"></figure>在我们的业务关系图中,部门和研究所实体是多对一的关系,同时我们还是采用双向关联来说明问题
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,优化了性能,同时也取得了相应的值。