JPA 查询可以将结果作为 Java Map 返回吗? [英] Can a JPA Query return results as a 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屋!