Автор оригинала: Vlad Mihalcea.
В этой статье мы рассмотрим, как вы можете выполнять функции SQL с несколькими параметрами в запросах JPQL с помощью Hibernate. Недавно я наткнулся на это требование, отвечая на этот вопрос StackOverflow , который является нескончаемым источником вдохновения для статей в моем блоге.
Давайте рассмотрим, что мы используем следующую сущность Post
в нашем приложении:
Объект Post
отображается следующим образом:
@Entity(name = "Post") @Table(name = "post") public class Post { @Id private Long id; private String title; @Column(name = "created_on") private Timestamp createdOn; //Getters and setters omitted for brevity }
Наш бизнес-вариант использования требует, чтобы мы вызывали функцию DATE_TRUNC PostgreSQL следующим образом:
SELECT p.title AS col_0_0_, date_trunc( 'day', (p.created_on AT TIME ZONE ?) ) AS col_1_0_ FROM post p WHERE p.id = ?
Как объясняется в этой статье , перед использованием функции SQL в предложении SELECT запроса JPQL или API критериев нам сначала необходимо зарегистрировать эту функцию.
Лучший способ зарегистрировать функцию SQL в Hibernate-предоставить Конструктор метаданных
, как показано ниже:
public class SqlFunctionsMetadataBuilderContributor implements MetadataBuilderContributor { @Override public void contribute( MetadataBuilder metadataBuilder) { metadataBuilder.applySqlFunction( "date_trunc", new SQLFunctionTemplate( StandardBasicTypes.TIMESTAMP, "date_trunc('day', (?1 AT TIME ZONE ?2))" ) ); } }
Теперь вам нужно указать Hibernate использовать Конструктор метаданных функций Sql
с помощью свойства конфигурации hibernate.metadata_builder_contributor|/.
Вы можете либо добавить свойство hibernate.metadata_builder_contributor
в JPA persistence.xml
файл:
name="hibernate.metadata_builder_contributor" value="com.vladmihalcea.book.hpjp.hibernate.query.function.SqlFunctionsMetadataBuilderContributor"
Или, если вы используете Spring Boot, вы можете добавить следующую запись в файл конфигурации application.properties
:
spring.jpa.properties.hibernate.metadata_builder_contributor=com.vladmihalcea.book.hpjp.hibernate.query.function.SqlFunctionsMetadataBuilderContributor
Теперь, предполагая, что вы сохранили следующую Запись
сущность:
Post post = new Post(); post.setId(1L); post.setTitle( "High-Performance Java Persistence" ); post.setCreatedOn( Timestamp.valueOf( LocalDateTime.of(2018, 11, 23, 11, 22, 33) ) ); entityManager.persist(post);
Теперь вы можете использовать функцию DATE_TRUNC
SQL в запросе JPQL, подобном этому:
Tuple tuple = entityManager .createQuery( "select " + " p.title as title, " + " date_trunc(p.createdOn, :timezone) as creation_date " + "from " + " Post p " + "where " + " p.id = :postId", Tuple.class) .setParameter("postId", 1L) .setParameter("timezone", "UTC") .getSingleResult(); assertEquals( "High-Performance Java Persistence", tuple.get("title") ); assertEquals( Timestamp.valueOf( LocalDateTime.of(2018, 11, 23, 0, 0, 0) ), tuple.get("creation_date") );
И Hibernate собирается выполнить инструкцию SQL, которую мы хотели с самого начала:
Query:[" SELECT p.title AS col_0_0_, date_trunc( 'day', (p.created_on AT TIME ZONE ?) ) AS col_1_0_ FROM post p WHERE p.id=? "], Params:[( UTC, 1 )]
Круто, правда?
Использование свойства конфигурации hibernate.metadata_builder_contributor
– лучший способ зарегистрировать функцию SQL в Hibernate, и вы можете параметризовать функцию, чтобы передать ей свойства сущности и даже стандартные параметры запроса, как в случае параметра UTC
, который мы использовали при вызове функции DATE_TRUNCT
.