JPA 查询可以将结果作为 Java Map 返回吗? [英] Can a JPA Query return results as a Java Map?

查看:56
本文介绍了JPA 查询可以将结果作为 Java Map 返回吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们目前正在根据命名的 JPA 查询返回的两个字段手动构建一个 Map,因为 JPA 2.1 只提供了一个 getResultList() 方法:

We are currently building a Map manually based on the two fields that are returned by a named JPA query because JPA 2.1 only provides a getResultList() method:

@NamedQuery{name="myQuery",query="select c.name, c.number from Client c"}

HashMap<Long,String> myMap = new HashMap<Long,String>();

for(Client c: em.createNamedQuery("myQuery").getResultList() ){
     myMap.put(c.getNumber, c.getName);
}

但是,我觉得自定义映射器或类似的会更高效,因为此列表很容易包含 30,000 多个结果.

But, I feel like a custom mapper or similar would be more performant since this list could easily be 30,000+ results.

无需手动迭代即可构建地图的任何想法.

Any ideas to build a Map without iterating manually.

(我使用的是 OpenJPA,而不是休眠)

(I am using OpenJPA, not hibernate)

推荐答案

使用 JPA Query getResultStream 返回 Map 结果

从 JPA 2.2 版本开始,您可以使用 getResultStream Query 方法将 List 结果转换为 映射<整数,整数>:

Returning a Map result using JPA Query getResultStream

Since the JPA 2.2 version, you can use the getResultStream Query method to transform the List<Tuple> result into a Map<Integer, Integer>:

Map<Integer, Integer> postCountByYearMap = entityManager.createQuery("""
    select
       YEAR(p.createdOn) as year,
       count(p) as postCount
    from
       Post p
    group by
       YEAR(p.createdOn)
    """, Tuple.class)
.getResultStream()
.collect(
    Collectors.toMap(
        tuple -> ((Number) tuple.get("year")).intValue(),
        tuple -> ((Number) tuple.get("postCount")).intValue()
    )
);

使用 JPA 查询 getResultList 和 Java 流返回 Map 结果

如果您使用的是 JPA 2.1 或旧版本,但您的应用程序在 Java 8 或更新版本上运行,那么您可以使用 getResultList 并转换 List 到 Java 8 流:

Returning a Map result using JPA Query getResultList and Java stream

If you're using JPA 2.1 or older versions but your application is running on Java 8 or a newer version, then you can use getResultList and transform the List<Tuple> to a Java 8 stream:

Map<Integer, Integer> postCountByYearMap = entityManager.createQuery("""
    select
       YEAR(p.createdOn) as year,
       count(p) as postCount
    from
       Post p
    group by
       YEAR(p.createdOn)
    """, Tuple.class)
.getResultList()
.stream()
.collect(
    Collectors.toMap(
        tuple -> ((Number) tuple.get("year")).intValue(),
        tuple -> ((Number) tuple.get("postCount")).intValue()
    )
);

使用特定于 Hibernate 的 ResultTransformer 返回 Map 结果

另一种选择是使用 Hibernate Types 开源项目提供的 MapResultTransformer 类:

Map<Number, Number> postCountByYearMap = (Map<Number, Number>) entityManager.createQuery("""
    select
       YEAR(p.createdOn) as year,
       count(p) as postCount
    from
       Post p
    group by
       YEAR(p.createdOn)
    """)
.unwrap(org.hibernate.query.Query.class)
.setResultTransformer(
    new MapResultTransformer<Number, Number>()
)
.getSingleResult();

MapResultTransformer 适用于仍在运行的项目在 Java 6 上或使用较旧的 Hibernate 版本.

The MapResultTransformer is suitable for projects still running on Java 6 or using older Hibernate versions.

OP 说:

但是,我觉得自定义映射器或类似的会更高效因为这个列表很容易就有 30,000 多个结果.

But, I feel like a custom mapper or similar would be more performant since this list could easily be 30,000+ results.

这是一个糟糕的主意.您永远不需要选择 30k 条记录.这将如何适应 UI?或者,您为什么要对如此大量的记录进行操作?

This is a terrible idea. You never need to select 30k records. How would that fit in the UI? Or, why would you operate on such a large batch of records?

您应该使用查询分页,因为这将帮助您减少事务响应时间并提供更好的并发性.

You should use query pagination as this will help you reduce the transaction response time and provide better concurrency.

这篇关于JPA 查询可以将结果作为 Java Map 返回吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆