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

时间:2019-04-10 21:32:35

标签: 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 ));
        }

`我有SQL查询可以通过联接多个表(在我的情况下为13个表)来从各种表中提取某些数据,我能够成功地将所有结果返回,但是当我尝试将这些结果映射回DTO时,正在获取演员例外。我该如何克服这些例外?

B不能强制转换为类java.util.UUID和 无法将类java.math.BigDecimal强制转换为类java.lang.Integer

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

1 个答案:

答案 0 :(得分:1)

您可以use an @SqlResultSetMapping to convert each record in your result set to a 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")}))

我将此映射与查询一起使用,该查询从数据库中选择idtitleversionauthorName列。 @ConstructorResult注释描述了BookValue类的构造函数调用。 @ColumnResult批注定义了构造函数参数及其顺序。您需要确保实例化的类提供了与这些参数匹配的构造函数。

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


好的,现在让我们看一下类转换问题...

强制转换失败,因为这两个对象属于错误的类。 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);

BigDecimalInteger的转换要容易得多。您只需要在intValueExact()上调用BigDecimal方法,例如row[6].intValueExact();