java - 使用 HQL 急切加载嵌套关联
问题描述
我有以下模型:
public class BaseModel {
List<DataA> lazyCollectionA;
List<DataB> lazyCollectionB;
}
public class DataA {
OtherEntity otherEntity;
}
public class OtherEntity {
List<DataC> lazyCollectionC;
}
当我访问特定页面时,我需要使用所有这些数据。这正在创建一个性能选择 n+1 问题。
我已经通过急切地使用以下方法获取集合来部分解决了这个问题:
List<BaseModel> result = entityManager.createQuery(
"select m from BaseModel m " +
"left join fetch m.lazyCollectionA " +
"where m.id in (:ids) ", BaseModel.class)
.setParameter("ids", ids)
.getResultList();
result = entityManager.createQuery(
"select m from BaseModel m " +
"left join fetch m.lazyCollectionB " +
"where m.id in (:ids) ", BaseModel.class)
.setParameter("ids", ids)
.getResultList();
请注意,我必须执行 2 个查询而不是仅 1 个,否则我会得到一个MultipleBagFetchException
.
但是,我急切地加载lazyCollectionA.otherEntity.lazyCollectionC
. 我尝试了几种查询变体来尝试急切地获取结果,但是当otherEntity.lazyCollectionC
被访问时,选择 n+1 问题不断浮出水面。
我认为这应该可行,但不幸的是它不是:
entityManager.createQuery(
"select a from BaseModel m " +
"left join m.lazyCollectionA a " +
"left join fetch a.otherEntity o " +
"left join fetch o.lazyCollectionC " +
"where m.id in (:ids) ", BaseModel.class)
.setParameter("ids", ids)
.getResultList();
你有什么想法为什么这不起作用?
此外,我不完全了解我的前 2 个查询是如何加载lazyCollectionA
和lazyCollectionB
工作的。我的意思是,由于它们是在不同时间加载的,我希望只有最后一个查询才会有加载的实例。是不是因为hibernate正在缓存结果,因此不需要再次查询数据库?
感谢您的任何帮助,您可以提供!
解决方案
我假设您的模型之间的所有连接都是@OneToMany。在这种情况下,您可以尝试这样的事情:
@Autowired
private EntityManager em;
@Transactional
public List<BaseModel> getAllByThreeQueries() {
List<Long> ids = Arrays.asList(1L);
List<BaseModel> first = em.createQuery(
"select distinct m from BaseModel m " +
"left join fetch m.lazyCollectionB " +
"where m.id in (:ids) ", BaseModel.class)
.setParameter("ids", ids)
.getResultList();
List<BaseModel> second = em.createQuery(
"select distinct m from BaseModel m " +
"left join fetch m.lazyCollectionA a " +
"left join fetch a.otherEntity o " +
"where m in (:models) ", BaseModel.class)
.setParameter("models", first)
.getResultList();
em.createQuery("select distinct a from BaseModel m " +
"left join m.lazyCollectionA a " +
"left join fetch a.otherEntity o " +
"left join fetch o.lazyCollectionC " +
"where m in (:models) ", DataA.class)
.setParameter("models", second)
.getResultList();
return second;
}
你有什么想法为什么这不起作用?
entityManager.createQuery(
"select a from BaseModel m " +
"left join m.lazyCollectionA a " +
"left join fetch a.otherEntity o " +
"left join fetch o.lazyCollectionC " +
"where m.id in (:ids) ", BaseModel.class)
.setParameter("ids", ids)
.getResultList();
因为在这种情况下你会得到一个 MultipleBagFetchException。你需要再做一个请求。
推荐阅读
- apache-kafka - Kafka 无法将分区状态从 OnlinePartition 更改为 OnlinePartition
- c# - 使用共享资源 XAML 覆盖 MVVM 中的特定命令按钮背景颜色
- java - JSONArray 到对象列表
- css - 如何确保与小型显示器的货币一致?
- matlab - 如何在matlab中生成概率3D图
- javascript - Javascript 二维数组:增加特定项目的值
- php - 在电子邮件中显示自定义数据,订单详情 woocommerce
- java - maven 仍然列出排除的依赖项
- rust - Rust Book 12.3 - 未解决的导入错误 [E4032]
- javascript - JavaScript 承诺无法解决