当前位置: 首页 > 知识库问答 >
问题:

强制Hibernate以在不更改映射的情况下急切地加载多个关联

夏侯航
2023-03-14

我有几个具有惰性一对多关系的实体(为简洁起见省略了逻辑):

@Entity
class A{
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "a_pk", nullable = false)
    List<B> blist = new ArrayList<>();

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "a_pk", nullable = false)
    List<C> clist = new ArrayList<>();

    @Column(name = "natural_identifier", nullable = false)
    private String id;
}

@Entity
class B{
}

@Entity
class C{
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "c_pk", nullable = false)
    List<D> dlist = new ArrayList<>();

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "c_pk", nullable = false)
    List<E> elist = new ArrayList<>();
}

@Entity
class D{
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "d_pk", nullable = false)
    List<F> flist = new ArrayList<>();
}

@Entity
class E{
}

@Entity
class F{
}

在某些情况下(非常罕见),我希望急切地加载A的实例及其所有关联。这样做的原因是,我想对该实例及其子实例整体进行一些修改,然后根据用户输入保存或丢弃它们。

如果我要根据需要加载东西,我必须根据用户请求将实体重新附加到新会话,但它们正在被修改,修改还不应该持久化。

所以我写了这样的东西:

Session session = sessionFactory.openSession();
s.beginTransaction();
Criteria c = session
                    .createCriteria(A.class)
                    .add(Restrictions.eq("id", someValue))
                    .setFetchMode("blist", SELECT)
                    .setFetchMode("clist", SELECT)
                    .createAlias("clist", "c")
                    .setFetchMode("c.dlist", SELECT)
                    .setFetchMode("c.elist", SELECT)
                    .createAlias("c.dlist", "d")
                    .setFetchMode("d.flist", SELECT);
A a = (A) c.uniqueResult();
session.close(); // line 150

a.getBlist().size(); // line 152 - debug
a.getClist().size(); // line 153 - debug

当我尝试访问内容时,我在第 152 行遇到异常:

org.hibernate.LazyInitializationException:
failed to lazily initialize a collection of role: 
A.blist, could not initialize proxy - no Session

如果我在条件中的所有地方都将fetch策略更改为< code>JOIN,我会得到相同的异常,但是是在< code >第153行(换句话说,加载第一个关联,而不是其他关联)。

编辑:Alexey Malev建议为别名设置获取模式;这似乎是真的。有以下标准:

Criteria c = session
                    .createCriteria(A.class)
                    .add(Restrictions.eq("id", someValue))
                    .setFetchMode("blist", JOIN)
                    .setFetchMode("clist", JOIN);

我得到了一个不同的例外:org.hibernate.loader.MultipleBagFetchException:无法同时获取第149行的多个袋子。因此,联接提取不是一种选择。

问题是,我如何加载整个东西?

Hibernate版本 4.2.12.最终版

共有3个答案

何雅惠
2023-03-14

记录在案,由于键值setFecthMode(key,...)
我使用表名而不是字段名,因此我也遇到了类似的问题。

宇文嘉勋
2023-03-14

我认为你使用了错误的获取模式。很可能您需要< code>JOIN。请尝试以下方法:

Criteria c = session
                .createCriteria(A.class)
                .add(Restrictions.eq("id", someValue))
                .setFetchMode("blist", JOIN)
                .setFetchMode("clist", JOIN)
                .createAlias("clist", "c")
                .setFetchMode("c", JOIN)
...//the same for others

注意 - 我也为别名添加了抓取模式。当您无法加载任何具有别名的列表时,行为会导致该猜测。

冯嘉荣
2023-03-14

我通过使用稍微不同的方法找到了解决原始问题的方法。引用Hibernate ORM留档:

有时代理或集合需要在关闭会话之前初始化。例如,您可以通过调用cat.getSex()或cat.getKittens(). size()来强制初始化。但是,这可能会让代码的读者感到困惑,并且对于泛型代码来说也不方便。

静态方法Hibernate.initialize()和Hibernate.isInitialized()为应用程序提供了一种方便的方式来处理延迟初始化的集合或代理。Hibernate.initialize(cat)将强制初始化代理cat,只要它的会话仍然打开。Hibernate.initialize(cat.getKittens())对小猫的集合也有类似的效果。

简单地获取一个惰性集合(a.getBlist())并不能使其加载-我最初犯了这个错误。如果我尝试从该集合中获取一些数据(获取项目,获取集合大小),它将加载。在该集合上调用<code>Hibernate.initialize(..)也会这样做。

因此,遍历实体关联和它们各自的关联等,并在会话内显式初始化它们(例如使用Hibernate.initialize())将加载会话关闭后在会话之外可用的所有内容。

该方法根本不使用条件获取模式(为什么它们不能按文档记录工作是另一个问题)。

这是一个明显的N 1问题,但我可以忍受。

 类似资料:
  • 问题内容: 我有一些实体具有一对一的懒惰关系(为简洁起见,省略了逻辑): 在某些(非常罕见)的情况下,我想热切地加载A及其所有关联的实例。这样做的原因是我想对该A实例及其整个子实例进行一些修改,然后根据用户输入保存或丢弃它们。 如果要按需加载内容,则必须根据用户请求将实体重新附加到新的会话,但是这些实体正在被修改,并且修改不应持久化。 所以我写这样的东西: 当我尝试访问内容时,出现以下异常: 如果

  • 我通过提示检查了它在EclipseLink中的工作情况: 这个链接http://blog.ringerc.id.au/2012/06/jpa2-is-very-inflexible-with-eagerlazy.html暗示通过Hibernate是不可能的,建议手动获取。但是,我无法理解如何通过HQL或标准来实现它,特别是如何获得不在实体上但仅存在于数据库上的child.parent_id列。即避

  • 问题内容: 我有http://mysite.com/index.php。 还有一个子菜单 主页=> http://mysite.com/index.php 关于我们=> http://mysite.com/about.us.php 产品=> http://mysite.com/products.php 但我希望http://mysite.com/index.php处理每个请求,并仅使用Ajax请求

  • 问题内容: 我有两个hibernate类:基类和具有附加字段的扩展类。(这些字段由其他表映射。) 例如,我有: 如何在Hibernate中对此进行映射?hibernate文档说明了三种类型的继承配置:每个类一个表,一个具有类型列的表和一个联接表-在此都不适用。 我之所以需要这样做,是因为类A来自通用框架,该框架已在多个项目中重用,而类B(和Node)是特定于一个项目的扩展- 不再使用。将来,我可能

  • 问题内容: 之前有人问过这个问题,从答案来看它看起来并不好。我想考虑一下此示例代码… 我的应用程序将当前项目加载到提供它的服务中。有几个控制器可以在不重新加载商品的情况下操纵商品数据。 如果尚未设置,我的控制器将重新加载该项目,否则,它将在控制器之间使用该服务中当前加载的项目。 问题 :我想为每个控制器使用不同的路径,而无需重新加载Item.html。 1)有可能吗? 2)如果这不可能,那么与我在