37

我有一个实体,其中包含:

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "assessment")
@OrderBy(value = "order ASC")
private List<AssessmentPart> assessmentParts = new LinkedList<>();

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "assessment")
private List<AssessmentText> texts = new LinkedList<>();

如您所见,有两个集合需要立即加载。这不起作用,hibernate 会抛出异常:

Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags

那是因为 Hibernate 不能一次性获取多个集合。但是,如果我将ListtoSetLinkedListtoHashSet这部分更改为可以正常工作,但会出现另一个更烦人的问题。

当我尝试使用以下方法从数据库中获取实体时:

entityManager.find(entityClass, primaryKey);

它失败了:

org.hibernate.AssertionFailure: null identifier

我确信我传递给find方法的 ID 不为空,我已经调试过并且我确信这一点。它以某种方式在 Hibernate 中消失了。

如果我将集合类型更改为LAZY一切都可以正常工作,但在某些情况下我需要使用EAGER.

有没有人有解决方案如何解决它?我可以有一个集合但防止发生断言错误,或者我可以有一个列表但以某种方式避免多个提取包错误。

我在用:

Hibernate 4.2.2.Final
Tomcat 7
JPA 2.0
JDK 1.7

编辑

我刚刚发现添加@Fetch(FetchMode.SELECT)解决了这个问题,我可以使用多个EAGER类型的列表,但是有没有通过不使用 Hibernate 特定的注释来解决这个问题?为什么它首先解决了这个问题?

4

2 回答 2

66

问题的根本原因在于,当 Hibernate 获取 SQL 查询结果时,没有简单的方法来判断哪个子元素属于哪个集合。有关示例的更详细说明,请参阅此博客条目。总结一下,您有以下解决方法:

  • 使用 subselect 分别加载每个集合@Fetch(FetchMode.SELECT)
  • 通过添加索引列强制使用列表而不是包@IndexColumn(name="LIST_INDEX")
  • 使用像 Set 这样的无序集合。
于 2013-07-10T09:53:58.760 回答
15

如果您正在使用 Hibernate 并且您不关心使用 Hibernate 注释:

使用以下命令注释您的集合字段:

@LazyCollection(LazyCollectionOption.FALSE)

请记住从 @OneToMany 注释中删除 fetchType 属性。

于 2013-07-10T09:56:28.083 回答