Как мы сопоставляем сложные результаты NativeQuery с объектами DTO с помощью java

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.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
3 550
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете возразить используйте @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")}))

Я использую это сопоставление с запросом, который выбирает столбцы id, title, version и authorName из базы данных. Аннотация @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);

Преобразование BigDecimal в Integer намного проще. Вам просто нужно вызвать метод intValueExact() на вашем BigDecimal, например. row[6].intValueExact();.

Спасибо, Янссен, я просмотрел статью, она очень полезна в нашей текущей базе кода, мы везде использовали SQLResultMapping, но это особый случай, когда у нас нет управляемого объекта для запроса. Это странный сценарий, мы присоединяемся к 12 таблицам и 12 таблицам. Мы разделили все сопоставления наших сущностей на 3 разных службы API, поэтому не можем сопоставлять все сущности при соединениях.

dummy 11.04.2019 17:59

Другие вопросы по теме