Seb*_*oek 4 java spring hibernate jpa jpql
JPQL / JPA / Hibernate等价于数据库功能是date_trunc('day', (entity.date AT TIME ZONE 'UTC'))什么?
我需要在Spring Boot应用程序中四舍五入到整天(和几周等),并使Hibernate运行在Postgresql数据库之上。这个查询可以在本地postgresql中进行,但是我还没有弄清楚如何在Hibernate中进行查询。时区(如“ UTC”,“欧洲/阿姆斯特丹”)和日期部分(如“日”,“年”)可能会有所不同,因此我不能仅将其设置为默认值。
我在Hibernate论坛上发现了一个古老的帖子,没有任何回复:https : //forum.hibernate.org/viewtopic.php? f =1& t =990451
我还发现了一个与StackOverflow相关的问题,发帖人直接希望在日期上选择某个时区。但是没有答复:HQL等同于Postgres的“时区的日期时间”
我的整个查询(没有where)看起来像这样,因此采用另一种方法也可以。
"SELECT NEW " + AggregateQueryEntity.class.getName() +
"(date_trunc('" + aggregationPeriod.toString() +
"', a.date), a.alertConfiguration.id.id, a.alertConfiguration.name, a.alertLevel, count(*)) from Alert a" +
whereClause.toString() +
" GROUP BY 1, a.alertConfiguration.id.id, a.alertConfiguration.name, a.alertLevel" + //column 1 is the truncated date
" ORDER BY 1, alertLevel DESC"
Run Code Online (Sandbox Code Playgroud)
编辑:对答案的评论。
弗拉德的答案很好,我对其进行了一些修改,以便将日期部分也作为变量。另外,我必须重写标准的Hibernate行为,该行为Date将按生成列,timestamp without timezone并timestamp with timezone通过将其放在我的列定义中来显式地创建它们:
@Column(columnDefinition = "TIMESTAMP WITH TIME ZONE") private Date date;
Run Code Online (Sandbox Code Playgroud)
有关更多信息,请参阅https://wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use_timestamp_.28without_time_zone.29
hibernate.jdbc.time_zone根据Vlad的其他博客文章https://vladmihalcea.com/how-to-store-date-time-and-timestamps-in-utc-time-zone-with-,使用Hibernate属性还是一个好主意。jdbc-and-hibernate /,然后在UTC中启动JVM。为了解决我所有的时区问题,我也必须这样做。
这是一个非常有趣的问题,因此我决定上一篇文章。
如用户指南中所述,yu可以使用以下任一EXTRACT功能:
List<Integer> days = entityManager
.createQuery(
"select extract( day from c.timestamp ) " +
"from Call c ", Integer.class )
.getResultList();
Run Code Online (Sandbox Code Playgroud)
或day功能:
List<Integer> days = entityManager
.createQuery(
"select day( c.timestamp ) " +
"from Call c ", Integer.class )
.getResultList();
Run Code Online (Sandbox Code Playgroud)
MetadataBuilderContributor如果还需要使用AT TIMEZONE,则需要注册PostgreSQL函数,如下所示:
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 'UTC'))"
)
);
}
}
Run Code Online (Sandbox Code Playgroud)
MetadataBuilderContributor使用JPA persistence.xml现在,您需要SqlFunctionsMetadataBuilderContributor通过hibernate.metadata_builder_contributor配置属性将其提供给Hibernate :
<property>
name="hibernate.metadata_builder_contributor"
value="com.vladmihalcea.book.hpjp.hibernate.query.function.SqlFunctionsMetadataBuilderContributor"
</property>
Run Code Online (Sandbox Code Playgroud)
MetadataBuilderContributor使用Spring Boot如果您使用的是Spring Boot,则需要在application.properties文件中添加以下配置:
spring.jpa.properties.hibernate.metadata_builder_contributor=com.vladmihalcea.book.hpjp.hibernate.query.function.SqlFunctionsMetadataBuilderContributor
Run Code Online (Sandbox Code Playgroud)
然后,假设您Post在数据库中具有以下实体:
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);
Run Code Online (Sandbox Code Playgroud)
您可以date_trunc像这样在JPQL中调用该函数:
Tuple tuple = entityManager
.createQuery(
"select p.title as title, date_trunc(p.createdOn) as creation_date " +
"from Post p " +
"where p.id = :postId", Tuple.class)
.setParameter("postId", 1L)
.getSingleResult();
assertEquals(
"High-Performance Java Persistence",
tuple.get("title")
);
assertEquals(
Timestamp.valueOf(
LocalDateTime.of(2018, 11, 23, 0, 0, 0)
),
tuple.get("creation_date")
);
Run Code Online (Sandbox Code Playgroud)
有关更多详细信息,请查看本文。
如果要自定义时区,只需将时区作为如下参数传递:
public static 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))"
)
);
}
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以date_trunc按以下方式调用该函数:
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();
Run Code Online (Sandbox Code Playgroud)
我在高性能Java持久性GitHub存储库中创建了以下测试用例,它们运行良好:
您可以使用以下语法简单地调用 postgres 函数 -
function('date_trunc', 'month', date)
Run Code Online (Sandbox Code Playgroud)
举个例子 -
select distinct w from YourModel w where studentId=:studentId and function('date_trunc', 'month', date) = :month
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1824 次 |
| 最近记录: |