Hibernate JPA - ManyToOne关系未填充

6

我目前正在将一个(工作中的)应用从使用EclipseLink迁移到Hibernate JPA,大部分情况下都很顺利,但我发现有一件事情无法解释,也想不到任何好的搜索词!

基本上,我有四个实体,它们之间形成了一个一对多关系链:

EntityA有一个EntityB列表,每个EntityB又有一个EntityC列表,每个EntityC又有一个EntityD列表

每个实体都有一个相反方向的多对一关系,因此:

EntityD有一个EntityC,EntityC有一个EntityB,EntityB有一个EntityA。

这是(为了清晰起见大大简化了):

@Entity
public class EntityA {
  @OneToMany (cascade = CascadeType.All, mappedBy = "entityA")
  private List<EntityB> entityBList;
  ...
}

@Entity
public class EntityB {
  @OneToMany (cascade = CascadeType.All, mappedBy = "entityB")
  private List<EntityC> entityCList;

  @JoinColumn (name = "ENTITY_A", referencedColumnName = "ENTITY_A_ID")
  @ManyToOne (cascade = CascadeType.PERSIST, optional = false)
  private EntityA entityA;
}

@Entity
public class EntityC {
  @OneToMany (cascade = CascadeType.ALL, mappedBy = "entityC")
  private List<EntityD> entityDList;

  @JoinColumn (name = "ENTITY_B", referencedColumnName = "ENTITY_B_ID")
  @ManyToOne (cascade = CascadeType.PERSIST, optional = false)
  private EntityB entityB;
}

@Entity
public class EntityD {
  @JoinColumn (name = "ENTITY_C", referencedColumnName = "ENTITY_C_ID")
  @ManyToOne (cascade = CascadeType.PERSIST, optional = false)
  private EntityC entityC;
}

我从数据库中获取一个EntityA(通过它的主键查找),因此获得了一个已经填充好的EntityA实例,其中包含一个PersistentBag用于我的List<EntityB>。当我解引用该List<EntityB>时,我看到了一个延迟加载的情况,同样地,当我从EntityB中获取EntityC时也是如此。
此时,一切都符合我的预期,我有一个EntityA、B和C,它们都完全填充了来自数据库的值,但是当我尝试从EntityC获取我的EntityD时,发现它是null。
在这一点上,我的实体管理器仍然是打开且活动状态的,即使我在获取EntityA后立即在调试器中查看它,我也可以遍历关系,直到EntityC,并再次看到'entityDList'为null。
到目前为止,我找到的唯一解决方法是使用:
EntityManager.refresh(entityC);

这段代码会填充所有元素,包括懒加载的PersistentBag实体DList。

因此,我的猜测是Hibernate只填充2级(或3级,取决于如何计算)的引用,然后放弃,尽管我不真正理解为什么会这样。有人能理解吗?

除了使用.refresh之外,是否有其他解决方案?有没有一种配置或注释值,可以让Hibernate完全填充引用对象?


Hibernate 配置参数 "max_fetch_depth" 的值是多少? - Matt Brock
3个回答

3
感谢这里的建议,它们可能相关,但对于我的特定情况没有帮助。
如果您正在阅读此内容并遇到同样的问题,尝试使用max_fetch_depth建议可能值得一试,但由于某种原因,它对我没有起作用(我想知道为什么?)。
同样,如果您的@OneToMany是Sets而不是Lists,则像Albert建议的那样进行急切获取或左连接可能有效,但显然Hibernate只允许您有一个最多可以被急切获取的List,如果您需要更多,请使用Sets。我没有尝试过,但我认为它可能解决了问题。
除非有更好的建议,否则我将继续调用refresh,这实际上可能更适合我的应用程序。

1

这确实很有趣。解决它的一种方法是查询对象A左连接获取到->B->C->D,如果您要遍历到对象D,这也更快。大致如下。

"from A left join fetch B left join fetch C left join fetch D"

你是否也尝试过将C->D的关系设置为eager?好奇那样会发生什么...


谢谢Albert,我尝试了两个建议,但都没有效果:(将关系设置为eager也没有效果,所以我尝试将所有三个关系(A->B->C->D)都设置为eager,但Hibernate报错“不能同时获取多个bag”。在JPQL中添加left join也有相同的结果。我在其他地方发现,这是因为我正在急切地获取的集合是列表,如果我将它们变成集合,它就会起作用,但我现在太懒了,所以我想我只能忍受刷新调用! - DaveyDaveDave

1

Hibernate文档中提到,您可以使用hibernate.max_fetch_depth属性进行设置。默认值为3。您可以在第47页的"Hibernate参考文档"中找到它。


谢谢你的回复 - 你知道 hibernate.properties 文件是否也被 Hibernate JPA 使用吗?我在 Hibernate 文档中找不到答案。我已经尝试将其更改为 4 和 0,但似乎没有任何效果... - DaveyDaveDave
好的,忽略上面的内容,因为将max_fetch_depth设置为0会破坏我的应用程序的其他部分 :) 将其设置为一个较高的数字(我尝试过4和10),似乎没有任何效果;我猜这是因为它只是一个最大值,而其他东西说服Hibernate在3个级别停止...? - DaveyDaveDave

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接