#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:
- Не устанавливайте никаких аннотаций/сопоставлений, связанных с гибернацией, в своем классе DTO, так как они уже есть в вашем классе сущностей.
- Убедитесь, что
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]