如何将Hibernate查询结果直接映射到CompanyStatusDTO对象?
当然可以直接把MySQL查询结果映射到你的CompanyStatusDTO对象里!作为Hibernate新手,我结合你的实体和DTO结构,给你介绍几种实用的实现方式:
方法1:JPQL查询 + 内存手动组装(最易理解)
这种方式适合新手先理解映射逻辑,通过JPQL查询出关联数据后,在内存中手动组装成嵌套的DTO结构。
步骤1:编写JPQL查询关联数据
String jpql = """ SELECT cs.companyStatusId, cs.companyStatusLabel, es.employeeStatusId, es.employeeStatusName FROM company_status cs JOIN company_status_employee_status cses ON cs.companyStatusId = cses.companyStatusId JOIN employee_status es ON cses.employeeStatusId = es.employeeStatusId """;
步骤2:执行查询并组装DTO
EntityManager entityManager = // 获取你的EntityManager实例 List<Object[]> rawResults = entityManager.createQuery(jpql).getResultList(); // 用Map来分组同一个CompanyStatus下的EmployeeStatus Map<Integer, CompanyStatusDTO> companyDtoMap = new HashMap<>(); for (Object[] row : rawResults) { Integer companyId = (Integer) row[0]; String companyLabel = (String) row[1]; Integer empId = (Integer) row[2]; String empName = (String) row[3]; // 从Map中获取或创建当前Company的DTO CompanyStatusDTO companyDto = companyDtoMap.getOrDefault(companyId, new CompanyStatusDTO()); companyDto.setCompanyStatusId(companyId); companyDto.setCompanyStatusLabel(companyLabel); // 创建EmployeeStatusDTO并添加到列表 EmployeeStatusDTO empDto = new EmployeeStatusDTO(); empDto.setEmployeeStatusId(empId); empDto.setEmployeeStatusName(empName); if (companyDto.getEmployeeStatusDTOs() == null) { companyDto.setEmployeeStatusDTOs(new ArrayList<>()); } companyDto.getEmployeeStatusDTOs().add(empDto); companyDtoMap.put(companyId, companyDto); } // 最终结果转换为List List<CompanyStatusDTO> finalDtoList = new ArrayList<>(companyDtoMap.values());
方法2:使用Hibernate自定义ResultTransformer(封装性更好)
Hibernate提供了ResultTransformer接口,可以把查询结果直接转换为目标DTO,把组装逻辑封装到Transformer中,代码更简洁。
步骤1:自定义ResultTransformer
public class CompanyStatusDTOResultTransformer implements ResultTransformer { private final Map<Integer, CompanyStatusDTO> companyDtoMap = new HashMap<>(); @Override public Object transformTuple(Object[] tuple, String[] aliases) { Integer companyId = (Integer) tuple[0]; String companyLabel = (String) tuple[1]; Integer empId = (Integer) tuple[2]; String empName = (String) tuple[3]; CompanyStatusDTO companyDto = companyDtoMap.getOrDefault(companyId, new CompanyStatusDTO()); companyDto.setCompanyStatusId(companyId); companyDto.setCompanyStatusLabel(companyLabel); EmployeeStatusDTO empDto = new EmployeeStatusDTO(); empDto.setEmployeeStatusId(empId); empDto.setEmployeeStatusName(empName); companyDto.setEmployeeStatusDTOs(Optional.ofNullable(companyDto.getEmployeeStatusDTOs()) .orElseGet(ArrayList::new)); companyDto.getEmployeeStatusDTOs().add(empDto); companyDtoMap.put(companyId, companyDto); return companyDto; } @Override public List transformList(List collection) { // 返回去重后的最终DTO列表 return new ArrayList<>(companyDtoMap.values()); } }
步骤2:使用Transformer执行查询
EntityManager entityManager = // 获取你的EntityManager实例 List<CompanyStatusDTO> dtoList = entityManager.createQuery(jpql) .unwrap(org.hibernate.query.Query.class) .setResultTransformer(new CompanyStatusDTOResultTransformer()) .getResultList();
方法3:实体关联 + ModelMapper/MapStruct转换(最优雅推荐)
如果允许修改实体类,建议先给CompanyStatus和EmployeeStatus建立多对多关联,然后用ModelMapper或MapStruct这类工具自动完成实体到DTO的转换,代码最简洁易维护。
步骤1:修改实体建立关联
@Entity(name = "company_status") @Table(name = "company_status") public class CompanyStatus implements Serializable { // 原有字段... @ManyToMany @JoinTable( name = "company_status_employee_status", joinColumns = @JoinColumn(name = "company_status_id"), inverseJoinColumns = @JoinColumn(name = "employee_status_id") ) private List<EmployeeStatus> employeeStatuses; // getter和setter }
步骤2:用ModelMapper自动转换
先引入ModelMapper依赖(Maven为例):
<dependency> <groupId>org.modelmapper</groupId> <artifactId>modelmapper</artifactId> <version>3.1.1</version> </dependency>
然后编写转换代码:
// 初始化ModelMapper ModelMapper modelMapper = new ModelMapper(); // 配置实体到DTO的映射规则(自动匹配字段名,这里可以省略,因为字段名一致) modelMapper.typeMap(CompanyStatus.class, CompanyStatusDTO.class) .addMapping(CompanyStatus::getEmployeeStatuses, CompanyStatusDTO::setEmployeeStatusDTOs); // 查询带关联的CompanyStatus数据 List<CompanyStatus> companies = entityManager.createQuery( "SELECT cs FROM company_status cs JOIN FETCH cs.employeeStatuses", CompanyStatus.class ).getResultList(); // 自动转换为DTO列表 List<CompanyStatusDTO> dtoList = companies.stream() .map(company -> modelMapper.map(company, CompanyStatusDTO.class)) .collect(Collectors.toList());
总结
- 新手可以先从方法1入手,理解数据组装的逻辑;
- 追求代码封装性可以用方法2;
- 长期维护推荐方法3,实体关联+自动映射工具的方式最优雅,减少手动代码量。
内容的提问来源于stack exchange,提问作者java12399900
相关产品推荐
相关产品推荐

