коллекция поиска по индексу в JPA @query

#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);