Hibernate 中的动态急切和延迟加载

问题描述 投票:0回答:2

我是 Hibernate 新手,但对 C# 中的实体框架有丰富的经验。我喜欢的一项功能是能够动态决定在查询中立即加载什么。例如,考虑班级和学生实体的一对多关系。

在“查看课程”页面上我可以执行以下操作:

context.Configuration.EnableLazyLoading = true; //default option
List<Classes> classes = context.Classes.ToList();

现在我可以很高兴地只显示班级信息,而无需浪费资源来收集学生数据。仅当用户单击“查看带有名册的班级”时,我才会执行以下操作:

context.Configuration.EnableLazyLoading = true;
List<Classes> classes = context.Classes.Include(c => c.Students).ToList();

通过这句话,我决定在这种特殊情况下,我想立即获取所有信息。不是两个查询。没有一百个查询。只需一个查询。尽管仅在几秒钟前加载了类,但所有这些都是如此。

我所有关于 Hibernate 的阅读都解释了如何在关系的配置文件中指定lazy="true|false",但我真的想要决定何时动态加载集合的选项。毕竟,我对购买时速仅 30 英里或 60 英里的汽车不感兴趣。我需要根据我所在的位置选择速度。

也许使用 fetch 模式作为 JOIN 的选项是可以接受的,因为在这种情况下它只会有两个查询(一个用于班级,一个用于学生),但我真的很喜欢在一个查询中完成所有操作的选项,特别是如果我有多个子集合要加载并且不想针对每个关系执行查询。我意识到一次性连接会创建需要流式传输的额外数据,但令我惊讶的是,这种级别的控制并不容易完成,或者可能完全不可用。

java hibernate orm lazy-evaluation eager
2个回答
2
投票

Hibernate 没有非常方便的动态获取方法。您可以通过以下方式控制它

  1. 使用通过 HQL 查询动态获取
    join fetch
    (如 @ThibaultClement 建议)。
  2. 使用 动态关联获取
    Criteria.setFetchMode()
  3. 使用 通过配置文件动态获取 以及
    @FetchProfile
    注释。
  4. 使用
    Hibernate.initialize()

您也可以参考HQL连接查询来急切地获取大量关系以获得更多想法。


0
投票

正如@v.ladynev 提到的,querydsl 是一个不错的选择。然而,在我看来,仍然没有一个干净的方法来处理它。

  1. 如果您使用 .select(...) ,结果将是一个元组而不是原始实体(未提及的字段默认为 null),这将导致编写一些样板代码以将其映射到原始实体。
  2. 与 querydsl 相关的另一种可能的解决方案是使用
    QueryProjection
    ,但它再次要求您编写具有不同可能性的单独类。
  3. 第三种解决方案可以是将所有连接保留为
    Fetch.LAZY
    ,然后使用
    JpaUtils.initialize()
    (或hibernate自己的方法)根据需要获取实体图。 (但就性能而言,这比直接使用
    join fetch
    更糟糕,后者只会进行 1 次 sql 调用)。
  4. 值得关注的第三个选项的另一种风格是使用 NamedEntityGraph 或 EntityGraph 来获取所需的部分。
© www.soinside.com 2019 - 2024. All rights reserved.