Возможно ли это: запрос JPA/Hibernate со свойством списка в методе DTO

#java #spring-boot #hibernate #jpa #hql

Вопрос:

В спящем режиме я хочу запустить этот запрос JPQL / HQL:

 select new AppointmentDTO(a.id,a.payment)
From Appointment a
WHERE a.hospitalId = :hospitalId
 

Назначение в класс

 @Entity
public class AppointmentDTO {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)

    private Integer appointmentId;

    @OneToMany
    @JoinColumn(name = "paymentId")
    private List<Payment> payment;

    public Integer getAppointmentId() {
        return appointmentId;
    }

    public List<Payment> getPayment() {
        return payment;
    }
    public AppointmentDTO(Integer appointmentId, List<Payment> payment) {
        super();
        this.appointmentId = appointmentId;
        this.payment = payment;
    }
}
 

Класс приема

 @Entity
@Table(name = "<tablename>")
public class Appointment {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY
    
    private Integer id;

    @OneToMany
    @JoinColumn(name = "paymentId")
    private List<Payment> payment;

//getter and setter
 

когда я выполняю,я получаю такую ошибку, как:

 Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate appropriate constructor on class [com.followMyDoctor.DTO.AppointmentDTO]. Expected arguments are: int, java.util.Collection [select new AppointmentDTO(a.id,a.payment) From ........ = :hospitalId]
 

В чем ошибка в выборе состояния, можно ли получить ожидаемый результат?
Можно ли получить одно целое в методе DTO

Комментарии:

1. Пожалуйста, уточните формулировку проблемы.

2. @krishnkantjaiswal мне нужно выполнить этот запрос с помощью DTO, чтобы выбрать новое назначениеdto(a.id,a.оплата) Из записи на прием a, ГДЕ a.hospitalId = :hospitalId

3. @NikolaiShevchenko Я уже добавил Целочисленный идентификатор назначения, Список<Оплата> оплата

Ответ №1:

Это невозможно, так как синтаксис конструктора работает только для передачи особых атрибутов. Если вы хотите это сделать, вам нужно «сгладить» и сгруппировать результирующий набор вручную с помощью потоков или a для каждого цикла.

Я думаю, что это идеальный вариант использования для представлений сущностей с сохранением блеска.

Я создал библиотеку, позволяющую легко сопоставлять модели JPA с пользовательским интерфейсом или абстрактными моделями, определенными классами, что-то вроде весенних прогнозов данных на стероидах. Идея заключается в том, что вы определяете свою целевую структуру(модель домена) так, как вам нравится, и сопоставляете атрибуты(геттеры) с помощью выражений JPQL с моделью сущности.

Модель DTO для вашего варианта использования может выглядеть следующим образом с представлениями сущностей Blaze-Persistence:

 @EntityView(Appointment.class)
public interface AppointmentDTO {
    @IdMapping
    Integer getAppointmentId();
    Set<PaymentDto> getPayment();

    @EntityView(Payment.class)
    interface PaymentDto {
        @IdMapping
        Integer getId();
        BigDecimal getAmount();
    }
}
 

Запрос-это вопрос применения представления сущности к запросу, самым простым из которых является просто запрос по идентификатору.

AppointmentDTO a = entityViewManager.find(entityManager, AppointmentDTO.class, id);

Интеграция данных Spring позволяет использовать ее почти как проекции данных Spring: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

 Page<AppointmentDTO> findAll(Pageable pageable);
 

Самое приятное то, что он будет получать только то состояние, которое действительно необходимо!

Ответ №2:

  1. Не устанавливайте никаких аннотаций/сопоставлений, связанных с гибернацией, в своем классе DTO, так как они уже есть в вашем классе сущностей.
  2. Убедитесь, что Payment объект относится к одному и тому же классу как в классах сущности, так и в классах DTO, если они не совпадают, то это несоответствие класса.

Вот как в идеале должен выглядеть ваш DTO:

 public class AppointmentDTO {

    private Integer appointmentId;

    private List<Payment> payment;

    public Integer getAppointmentId() {
        return appointmentId;
    }

    public List<Payment> getPayment() {
        return payment;
    }
    public AppointmentDTO(Integer appointmentId, List<Payment> payment) {
        super();
        this.appointmentId = appointmentId;
        this.payment = payment;
    }
}
 

Также при использовании классов, не являющихся сущностями, в JPQL укажите полное имя пакета вместе с классом, как показано ниже:

 SELECT new com.your.package.AppointmentDTO(...) FROM ...
 

Комментарии:

1. да что ж. Правильный ли это запрос SQL select?

2. Да, ваш JPQL кажется правильным, но, как я уже сказал, просто убедитесь, что класс Payment как в сущности, так и в классах DTO одинаковый. Определяемые пользователем классы являются проблемами в большинстве таких случаев.

3. ЕСЛИ я удалю ошибку аннотации типа «Вызвано: org.hibernate. Исключение сопоставления: Не удалось определить тип для: java.util. Список в таблице: Назначение для столбцов: [org.hibernate.сопоставление. Колонка(оплата)] »

4. О какой аннотации вы говорите? В DTO не требуется никаких аннотаций. Можете ли вы вставить полную трассировку стека этого исключения.

5. Вызвано: org.hibernate.hql.internal.ast.QuerySyntaxException: Не удается найти соответствующий конструктор в классе [com.followMyDoctor.DTO.Назначение]. Ожидаемые аргументы: int, java.util. Коллекция [выберите новое назначениеdto(a.id,a.оплата) Из com.followMyDoctor.модели. Запись на прием, где a.hospitalId = :hospitalId]