#spring #hibernate #jpa #spring-data-jpa
Вопрос:
У меня есть 2 сущности с одним отношением, как показано ниже,
public class Visit{
@OneToMany(mappedBy = "visit", fetch = FetchType.LAZY)
@OrderBy("updated_on DESC")
private List<StatusChange> statusHistory;
}
public class StatusChange{
@ManyToOne
@JoinColumn(name = "ms_visit_id")
private Visit visit;
@Column(name = "to_status")
@Enumerated(EnumType.STRING)
private VisitStatus toStatus;
}
Посещения могут иметь несколько статусов, таких как «создано», «отменено», «удалено» и т. Д. При каждом изменении статуса в таблицу StatusChange будет добавлена новая строка с записью, связанной с этим посещением (статус будет отменен) . Теперь мне нужен запрос для фильтрации посещений, для которых отменен последний статус, и с соответствующим идентификатором пользователя.
Я использую @запрос JPA. Я уже получил результат со следующим запросом.
@Query(value = "select vs1.visit from StatusChange vs1 where vs1.id in ("
" select max(vs2.id) from StatusChange vs2 "
" where vs2.visit.user.id = :userId"
" group by vs2.visit.id)"
" and vs1.toStatus in :status")
public List<MSVisit> findByUserAndStatus(@Param("userId") Long userId, @Param("status") List<Visit.VisitStatus> status);
Но я чувствую, что запрос может быть улучшен или есть какой-либо способ запросить что-то вроде,
"from Visit visit"
" where visit.statusHistory.get(0).toStatus in :status"
" and visit.user.id = :userId
Спасибо за вашу помощь.
Ответ №1:
Обычно эти запросы лучше всего моделируются с помощью боковых соединений, но Hibernate пока не поддерживает это. Обратите внимание, что, если вы не имели в виду что-то другое, ваш запрос неверен, так как максимальная агрегация основана на значении идентификатора, а не на значении updated_on. Не уверен, что это нарочно, но я бы предложил следующий запрос на случай, если вам действительно нужен последний визит.
@Query(value = "from Visit vs1 where vs1.user.id = :userId and (select max(h.updatedOn) from vs1.statusHistory h) >= ALL ("
" select max(h.updatedOn) from vs1.statusHistory h "
" and vs1.toStatus in :status")
public List<MSVisit> findByUserAndStatus(@Param("userId") Long userId, @Param("status") List<Visit.VisitStatus> status);