我们如何使用 java 将复杂的 NativeQuery 结果映射到 DTO 对象

dum*_*mmy 0 java sql hibernate jpa

Query query = em.createNativeQuery(STUDENT_QUERY_WITH_PARAMS);
        query.setParameter("studentId", stduentId);
        query.setParameter("startDate", valueOf(startDate), TemporalType.DATE);
        query.setParameter("endDate", valueOf(endDate), TemporalType.DATE);
        List<Object[]> resultList = query.getResultList();

        List<StudentDepartmentCatDTO> result = new ArrayList<>(resultList.size());
        for (Object[] row : resultList) {
            result.add(new StudentDepartmentCatDTO((String)row[0], (String)row[1], (String)row[2], null,(UUID)row[4], (Integer)row[5], (Integer)row[6], (Integer)row[7], (Integer)row[8], null, null, null, null ));
        }
Run Code Online (Sandbox Code Playgroud)

`我有 SQL 查询通过加入多个表(在我的例子中是 13 个表)来从各种表中提取某些数据,我能够成功地取回所有结果,但是当我尝试将这些结果映射回 DTO 时,我正在转换例外。我如何克服这些异常?

B 不能转换为类 java.util.UUID 和类 java.math.BigDecimal 不能转换为类 java.lang.Integer

由于所有结果都来自各种表,我没有找到使用 SqlResultSetMapping 执行此操作的方法,因为没有任何托管实体可以直接映射到结果。有一个更好的方法吗?我如何解决这些强制转换异常?我可以创建非托管实体以将所有结果映射到它吗?如何将 sql 结果提取到我的 DTO。

Tho*_*sen 9

您可以使用@SqlResultSetMapping将结果集中的每条记录转换为 DTO对象。但这将需要一个额外的构造函数,这样您就不需要将任何参数设置为null.

这是此类映射的示例。如您所见,您需要通过名称引用结果集中的元素,但您没有共享您的查询。因此,我无法根据您的查询调整示例。

@SqlResultSetMapping(
        name = "BookValueMapping",
        classes = @ConstructorResult(
                targetClass = BookValue.class,
                columns = {
                    @ColumnResult(name = "id", type = Long.class),
                    @ColumnResult(name = "title"),
                    @ColumnResult(name = "version", type = Long.class),
                    @ColumnResult(name = "authorName")}))
Run Code Online (Sandbox Code Playgroud)

我用这种映射与选择一个查询idtitleversionauthorName从数据库中的列。该@ConstructorResult注解描述的构造函数调用BookValue的类。该@ColumnResult注解定义构造函数的参数和它们的顺序。您需要确保实例化的类提供与这些参数匹配的构造函数。

@SqlResultSetMapping是 JPA 中一个强大而灵活的特性。我在这里详细解释:https : //thoughts-on-java.org/result-set-mapping-constructor-result-mappings/


好的,现在让我们来看看 class cast 问题......

转换失败,因为这两个对象属于错误的类。row[4]似乎是byte[]和一个row[6/7/8](或全部)似乎是一个BigInteger。

此代码片段应该可以帮助您将 byte[] 转换为 UUID:

ByteBuffer bb = ByteBuffer.wrap(bytes);
long high = bb.getLong();
long low = bb.getLong();
UUID uuid = new UUID(high, low);
Run Code Online (Sandbox Code Playgroud)

aBigDecimal到 an的转换Integer要容易得多。你只需要调用intValueExact()你的方法BigDecimal,例如row[6].intValueExact();