JPA Criteria API

JPA Criteria API

Выборка записей с максимальной датой в разрезе значений определённого поля

На SQL выражение выглядит так (записи с максимальным create_timestamp у каждого sender’а):

select * from
    incoming_swift oq
join
    (
        select
            max(create_timestamp) as create_timestamp, sender
        from
            incoming_swift
        group by sender
    ) sq
    on oq.sender = sq.sender and oq.create_timestamp = sq.create_timestamp;

Но т.к. criteria api поддерживает подзапросы полько в секции where, то можно реализовать только такой запрос (будет делать то же самое):

select
    *
from
    incoming_swift oq
where
    (
        select
            max(sq.create_timestamp)
        from
            incoming_swift sq
        where
            sq.sender=oq.sender
    )=oq.create_timestamp;

Если реализовать интерфейс Specification, то он будет выглядеть так:

import org.springframework.data.jpa.domain.Specification;
import javax.persistence.criteria.*;

public class SwiftSpecification implements Specification<IncomingSwift> {
    private final GetSwiftRequestDto dto;

    public SwiftSpecification(GetSwiftRequestDto dto) {
        this.dto = dto;
    }

    @Override
    public Predicate toPredicate(Root<IncomingSwift> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
        List<Predicate> predicateList = new ArrayList<>();

		Subquery<LocalDateTime> subQuery = query.subquery(LocalDateTime.class);
		Root<IncomingSwift> sq = subQuery.from(IncomingSwift.class);
		subQuery.select(criteriaBuilder.greatest(sq.get(createTimestamp)))
				.where(criteriaBuilder.equal(sq.get(sender), root.get(sender)));

		predicateList.add(criteriaBuilder.equal(subQuery, root.get(createTimestamp)));

        return criteriaBuilder.and(predicateList.toArray(new Predicate[0]));
    }
}

При этом, это поля из модели, сгенерированные maven-плагином:

<plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-compiler-plugin</artifactId>
     <configuration>
         <annotationProcessorPaths>
             <dependency>
                 <groupId>org.hibernate</groupId>
                 <artifactId>hibernate-jpamodelgen</artifactId>
                 <version>${hibernate.version}</version>
             </dependency>
         </annotationProcessorPaths>
         <compilerArgs>
             <arg>-Xlint:all</arg>
         </compilerArgs>
     </configuration>
 </plugin>

Выборка записей с максимальной датой

На SQL выражение выглядит так (записи с максимальным create_timestamp):

select
    *
from
    incoming_swift oq
where
    (
        select
            max(sq.create_timestamp)
        from
            incoming_swift sq
    )=oq.create_timestamp;

Если реализовать интерфейс Specification, то он будет выглядеть так:

import org.springframework.data.jpa.domain.Specification;
import javax.persistence.criteria.*;

public class SwiftSpecification implements Specification<IncomingSwift> {
    private final GetSwiftRequestDto dto;

    public SwiftSpecification(GetSwiftRequestDto dto) {
        this.dto = dto;
    }

    @Override
    public Predicate toPredicate(Root<IncomingSwift> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
        List<Predicate> predicateList = new ArrayList<>();

		Subquery<LocalDateTime> subQuery = query.subquery(LocalDateTime.class);
        Root<IncomingSwift> subRoot = subQuery.from(IncomingSwift.class);
        subQuery.select(criteriaBuilder.greatest(subRoot.get(createTimestamp)));
        predicateList.add(criteriaBuilder.equal(root.get(createTimestamp), subQuery));

        return criteriaBuilder.and(predicateList.toArray(new Predicate[0]));
    }
}


Выборка записей с полем, значения которого входят в список значений

По аналогии с предыдущими примерами:

predicateList.add(root.get(type).in(dto.getTypes()));

Выборка записей с полем, значение которого равно указанному значению

По аналогии с предыдущими примерами:

predicateList.add(criteriaBuilder.equal(root.get(id), dto.getId()));

Выборка записей с полем, значение даты которого равно или более указанной даты

predicateList.add(criteriaBuilder.greaterThanOrEqualTo(root.get(Activity_.createdDate).as(LocalDateTime.class), dto.getCreatedDateFrom()));

Case insensitive like

predicateList.add(criteriaBuilder.like(criteriaBuilder.lower(root.get(Activity_.userName)), "%" + dto.getUserName().trim().toLowerCase() + "%"));
(Просмотрено 156 раз, 1 раз за сегодня)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *