减少包含实体的JPQL POJO的查询数量

dan*_*car 8 postgresql hibernate jpa hql jpql

实体关系:交易(@ManyToOne - 默认情况下急切) - >账户

String sql = "SELECT new com.test.Pojo(t.account, SUM(t.value)) FROM Transaction t GROUP BY t.account";
List list = entityManager.createQuery(sql).getResultList();
Run Code Online (Sandbox Code Playgroud)

默认情况下,使用Hibernate实现的JPA将生成1 + n个查询.n个查询用于延迟加载帐户实体.

如何通过单个查询急切地使用此查询并加载所有内容?sql等价物就像是

SELECT account.*, SUM(t.value) FROM transactions JOIN accounts on transactions.account_id = accounts.id GROUP BY account.id
Run Code Online (Sandbox Code Playgroud)

,一种在PostgreSQL上运行良好的语法.根据我的发现,Hibernate正在生成一个可以证明延迟加载的查询.

SELECT account.id, SUM(t.value) FROM transactions JOIN accounts on transactions.account_id = accounts.id GROUP BY account.id
Run Code Online (Sandbox Code Playgroud)

JMS*_*lla 4

尝试将该@ManyToOne字段标记为惰性:

@ManyToOne(fetch = FetchType.LAZY)
private Account account;
Run Code Online (Sandbox Code Playgroud)

JOIN FETCH并使用字段之一更改您的查询,account以仅生成一个包含您所需的查询,如下所示:

String sql = "SELECT new com.test.Pojo(acc, SUM(t.value)) "
    + "FROM Transaction t JOIN FETCH t.account acc GROUP BY acc";
Run Code Online (Sandbox Code Playgroud)

更新:

抱歉,你是对的, 的 fetch 属性@ManyToOne不是必需的,因为在 Hibernate 中这是默认值。不起作用JOIN FETCH,它导致QueryException:“查询指定的联接获取,但获取的关联的所有者不存在”。

我尝试过其他一些方法,避免执行 n + 1 次查询的最简单方法是Pojo从查询中删除对象的创建并处理结果列表,手动创建对象:

String hql = "SELECT acc, SUM(t.value)"
  + " FROM " + Transaction.class.getName() +  " t"
  + " JOIN t.account acc"
  + " GROUP BY acc";

Query query = getEntityManager().createQuery(hql);
List<Pojo> pojoList = new ArrayList<>();
List<Object[]> list = query.getResultList();

for (Object[] result : list)
    pojoList.add(new Pojo((Account)result[0], (BigDecimal)result[1]));
Run Code Online (Sandbox Code Playgroud)