1

У меня есть объект со встроенным идентификатором, который содержит поле id и version.Фильтрация объектов в поле версии с помощью JPA Критерии-API

@Entity 
@Table(name = "MyEntity") 
public class MyEntity { 
    @EmbeddedId 
    private MyEntityEmbeddedId compositeId; 

    @Column 
    private DateTime begin; 

    @Column 
    private DateTime end; 

} 

@Embeddable 
public class MyEntityEmbeddedId { 
    @Column(name = "ID", nullable = false, updatable = false) 
    private Long id; 

    @Column(name = "VERSION", nullable = false, updatable = false) 
    private Long version; 

    public MyEntityEmbeddedId() {} 

} 

Мне нужно запросить базу данных с некоторыми критериями в качестве фильтра для объекта. Например, я запрошу с датой и списком идентификаторов.

List<MyEntity> listEntities = getMyEntities(List<Long> ids, DateTime date); 

мне удалось создать запрос, который retreives все объекты, для которых их идентификатор в списке идентификаторов и что при условии, дата между свойствами «начать» и «конец» дата в MyEntity.

Но поскольку этот объект имеет составной идентификатор, существует много MyEntity с тем же «id», который может соответствовать параметрам запроса. Я хочу добавить еще один фильтр, чтобы восстановить MyEntity с самым высоким номером «версии», если их много с одним и тем же «id».

Вот пример того, что может быть в базе данных:

+------+-----------+--------------------+ 
| id | version | began | end | 
+------+-----------+--------------------+ 
| 1 | 1   | ...  | ... | 
| 1 | 2   | ...  | ... | 
| 1 | 3   | ...  | ... | 
| 2 | 1   | ...  | ... | 
| 2 | 2   | ...  | ... | 
+------+-----------+--------------------+ 

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

+------+-----------+--------------------+ 
| id | version | began | end | 
+------+-----------+--------------------+ 
| 1 | 3   | ...  | ... | 
| 2 | 2   | ...  | ... | 
+------+-----------+--------------------+ 

в настоящее время я делаю запрос, но я фильтровать версию внутри метода внутри моей службы, но я предпочел бы, если версия уже фильтруется в запросе к базе данных. Мне не нужно возвращать записи, которые будут отброшены после фильтрации.

Я ищу способ самостоятельно объединиться с API-критериями JPA.

В следующей ссылке кажется, что принятый ответ разрешит мою проблему, я задаюсь вопросом, как я буду переводить предложенный SQL в API-критерии JPA.

SQL Select only rows with Max Value on a Column

select yt1.* 
from yourtable yt1 
left outer join yourtable yt2 
on (yt1.id = yt2.id and yt1.rev < yt2.rev) 
where yt2.id is null; 

Мой вопрос, когда я пытаюсь создать соединение. Вам необходимо предоставить свойство из первого объекта, который ссылается на второй объект в соединении. Поскольку я хочу сделать самостоятельное соединение, в моей сущности нет свойства, указывающего на себя.

Join<MyEntity, MyEntity> selfJoin = root.join(MyEntity_.???); 

Как вы видите, я использую статическую метамодель MyEntity. Это способ сделать самообслуживание с API-интерфейсом JPA?

Возможно, есть еще один способ для создания моего запроса, чем с самостоятельным левым соединением, как это предлагается в другом вопросе stackoverflow.

Я использую спецификацию Spring Data JPA для построения моего запроса с помощью Predicate. Затем используется findAll (спецификация). У меня уже есть два других метода спецификации для генерации предиката для forIds() и withDate(). Это позволяет мне создавать запросы с «неопределенным числом» параметров, предоставляемых пользователем.

public static Specification<MyEntity> withIdAndDate(final List<Long> ids, 
     final DateTime date) { 
    return new Specification<MyEntity>() { 

     @Override 
     public Predicate toPredicate(Root<MyEntity> root, CriteriaQuery<?> query, 
       CriteriaBuilder cb){ 
      Join<MyEntity, MyEntity> selfJoin = root.join(); 
      Predicate pIds = withIds(ids).toPredicate(root, query, cb); 
      Predicate pDate = withDate(date).toPredicate(root, query, cb); 

      return cb.and(pIds, pDate); 
     } 

    }; 
} 

Большое спасибо за вашу помощь и предложение!

ответ

0

Наконец, мне удалось найти способ фильтровать MyEntity в последней версии с API-интерфейсом JPA, поэтому я поделюсь с вами своим кодом, надеясь, что это поможет кому-то здесь.

public static Specification<MyEntity> withIdAndDate(final List<Long> ids, 
     final DateTime date) { 
    return new Specification<MyEntity>() { 

     @Override 
     public Predicate toPredicate(Root<MyEntity> root, CriteriaQuery<?> query, 
       CriteriaBuilder cb){ 

      Subquery<Long> subqueryVersion = query.subquery(Long.class); 
      Root<MyEntity> entity1 = subqueryVersion.from(MyEntity.class); 

      Expression<Long> expMaxVersion = cb.greatest(entity1 
       .get(MyEntity_.compositeId).get(MyEntityEmbeddedId_.version)); 
      Expression<Long> expIdRoot = root.get(MyEntity_.compositeId) 
       .get(MyEntityEmbeddedId_.id); 
      Expression<Long> expIdEntity1 = entity1 .get(MyEntity_.compositeId) 
       .get(MyEntityEmbeddedId_.id); 
      Expression<Long> expVersionRoot = root.get(MyEntity_.compositeId) 
       .get(MyEntityEmbeddedId_.version); 

      Predicate pId = cb.equal(expIdRoot, expIdEntity1); 
      Predicate pIds = withIds(ids).toPredicate(entity1, query, cb); 
      Predicate pDate = withDate(date).toPredicate(entity1, query, cb); 

      subqueryVersion.select(expMaxVersion); 
      subqueryVersion.where(pId, pIds, pDate); 

      Predicate pQuery = cb.equal(expVersionRoot, subqueryVersion); 

      return cb.and(pQuery); 
     } 

    }; 
} 

В следующей ссылке, принятый ответ поможет мне построить мой запрос в JPQL и после этого, мне удалось перевести его в JPA Criteria API. Я удаляю последнюю часть запроса, которая является частью «AND NOT EXISTS». JPA Select latest instance for each item

 Смежные вопросы

  • Нет связанных вопросов^_^