Hibernate映射问题:无法使用TypedQuery映射DTO求助
使用TypedQuery映射DTO失败问题排查
问题描述
在使用TypedQuery映射DTO时遇到问题,尝试多种方法后映射仍未按预期工作。已确认参数设置正确,子表关系定义无误,请求协助排查代码错误。
Service类代码
public OrganizationDetailDTO getOrganizationDetailForAgent(Long anOrganizationId) throws ApplicationException, AccessDeniedException { // Create DTO and necessary objects OrganizationDetailDTO organizationDTO; try { // Log request information LOGGER.info("#2 Get OrganizationByIdWithParent request received in Organization Service with OrganizationId: " + anOrganizationId); organizationDTO = this.findOrganizationDetailDTO(OrganizationDetailDTO.class, anOrganizationId); // Retrieve organization by ID // Check if organization exists if (organizationDTO == null) { LOGGER.info("No Organization Found Against Id " + anOrganizationId); throw new Exception("No Organization Found Against Id"); } } public <T> T findOrganizationDetailDTO(Class<T> organizationDetailDTOClass, Long id) { String queryString = "SELECT NEW com.alsharqi.org.organization.OrganizationDetailDTO(o.id, o.squad, o.squadId, o.creditHoldOverride, o.creditLimit, o.creditTermName, " + "o.creditTerm, o.vatRegNumber, o.isActive, o.accountManagerUUID, o.accountManagerName, o.logisticManagerUUID, o.logisticManagerName, o.escalationManagerUUID, " + "o.escalationManagerName,o.portalAccess,o.systemActive,o.parent.id) FROM Organization o WHERE o.id = :id"; TypedQuery<T> query = entityManager.createQuery(queryString, organizationDetailDTOClass); query.setParameter("id", id); try { return query.getSingleResult(); } catch (NoResultException e) { return null; } }
OrganizationDetailDTO类代码
@Setter @Getter @NoArgsConstructor public class OrganizationDetailDTO { @Column(name = "organization_id") private Long id; private String squad; private String squadId; private String creditHoldOverride; private Double creditLimit; private String creditTermName; private Double creditTerm; private String vatRegNumber; private boolean isActive; private Long accountManagerUUID; private String accountManagerName; private Long logisticManagerUUID; private String logisticManagerName; private Long escalationManagerUUID; private String escalationManagerName; private boolean portalAccess; private int systemActive; private Long parent; public OrganizationDetailDTO(Long id, String squad, String squadId, String creditHoldOverride, Double creditLimit, String creditTermName, Double creditTerm, String vatRegNumber, boolean isActive, Long accountManagerUUID, String accountManagerName, Long logisticManagerUUID, String logisticManagerName, Long escalationManagerUUID, String escalationManagerName,boolean portalAccess,Integer systemActive,Long parent) { this.id = id; this.squad = squad; this.squadId = squadId; this.creditHoldOverride = creditHoldOverride; this.creditLimit = creditLimit; this.creditTermName = creditTermName; this.creditTerm = creditTerm; this.vatRegNumber = vatRegNumber; this.isActive = isActive; this.accountManagerUUID = accountManagerUUID; this.accountManagerName = accountManagerName; this.logisticManagerUUID = logisticManagerUUID; this.logisticManagerName = logisticManagerName; this.escalationManagerUUID = escalationManagerUUID; this.escalationManagerName = escalationManagerName; this.portalAccess=portalAccess; this.systemActive=systemActive; this.parent=parent; } private ContactDTO adminInfo = new ContactDTO(); }
实体类

异常信息
com.hp.org.util.ApplicationException: org.hibernate.QueryException: could not instantiate class [com.hp.org.organization.OrganizationDetailDTO] from tuple at com.hp.org.api.OrganizationService.getOrganizationDetailForAgent(OrganizationService.java:3347) ~[main/:?] at com.hp.org.api.OrganizationService$$FastClassBySpringCGLIB$$59b45cac.invoke(<generated>) ~[main/:?] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-5.0.13.RELEASE.jar:5.0.13.RELEASE] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746) ~[spring-aop-5.0.13.RELEASE.jar:5.0.13.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.0.13.RELEASE.jar:5.0.13.RELEASE] at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) ~[spring-tx-5.0.13.RELEASE.jar:5.0.13.RELEASE] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) ~[spring-tx-5.0.13.RELEASE.jar:5.0.13.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.13.RELEASE.jar:5.0.13.RELEASE] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.0.13.RELEASE.jar:5.0.13.RELEASE] at com.hp.org.api.OrganizationService$$EnhancerBySpringCGLIB$$c94a2754.getOrganizationDetailForAgent(<generated>) ~[main/:?]
问题排查与解决方案
1. 核心问题:JPQL中DTO全类名不匹配
异常显示实际要实例化的DTO是com.hp.org.organization.OrganizationDetailDTO,但Service类的JPQL查询里写的是com.alsharqi.org.organization.OrganizationDetailDTO,包名不一致导致Hibernate找不到正确的构造器,无法实例化DTO。
解决:修改JPQL中的DTO全类名,替换为实际的包路径:
String queryString = "SELECT NEW com.hp.org.organization.OrganizationDetailDTO(o.id, o.squad, o.squadId, o.creditHoldOverride, o.creditLimit, o.creditTermName, " + "o.creditTerm, o.vatRegNumber, o.isActive, o.accountManagerUUID, o.accountManagerName, o.logisticManagerUUID, o.logisticManagerName, o.escalationManagerUUID, " + "o.escalationManagerName,o.portalAccess,o.systemActive,o.parent.id) FROM Organization o WHERE o.id = :id";
2. 构造器参数类型匹配问题
DTO构造器中systemActive参数是Integer类型,但DTO字段定义是int,同时实体中systemActive如果是int类型,JPQL返回的是基本类型int,虽然自动装箱可以处理,但为了避免潜在问题,建议统一类型:
解决:将构造器中的Integer systemActive改为int systemActive:
public OrganizationDetailDTO(Long id, String squad, String squadId, String creditHoldOverride, Double creditLimit, String creditTermName, Double creditTerm, String vatRegNumber, boolean isActive, Long accountManagerUUID, String accountManagerName, Long logisticManagerUUID, String logisticManagerName, Long escalationManagerUUID, String escalationManagerName,boolean portalAccess,int systemActive,Long parent) { // ... 原有赋值逻辑不变 this.systemActive=systemActive; }
3. 可选关联字段处理
如果实体中parent是可选关联(即允许为null),o.parent.id可能返回null,此时构造器中parent参数为Long是允许的(支持null),但要确保实体中parent的关联映射正确(比如@ManyToOne(optional = true))。
内容的提问来源于stack exchange,提问作者HassanUsman
相关产品推荐
相关产品推荐

