渴望获取嵌套(递归)对象 - Hibernate

Eager fetch nested (recursive) objects - Hibernate

我想急切地填充我的对象层次结构。问题是 Hibernate 在某些时候停止获取;它留下未填充的关系字段(列表)。

层次结构是(省略了一些代码,如 id、getter,这部分似乎没问题,希望如此):

public class User {
    private Container container;

    @OneToOne(fetch = FetchType.EAGER)
    public Container getContainer() {
        return container;
    }
}


public class Container {
    private List<Backpack> backpacks;
    private List<Item> items;

    @OneToMany(fetch = FetchType.EAGER, mappedBy="container")
    @Fetch(FetchMode.SELECT)
    private List<Item> getItems() {
        return items;
    }


    @OneToMany(fetch = FetchType.EAGER, mappedBy="container")
    @Fetch(FetchMode.SELECT)
    private List<Backpack> getBackpacks() {
        return backpacks;
    }
}


public class Backpack {
    ...
    private Container container;            /* Unidirectional relationship - ID of container which contains this backpack */
    private Container backpackContainer;    /* Unidirectional relationship - ID of container which represents backpack's storge */
    ...

    @NotNull
    @ManyToOne(fetch = FetchType.EAGER)
    @Fetch(FetchMode.SELECT)
    public Container getContainer() {
        return container;
    }


    @OneToOne(fetch = FetchType.EAGER)
    @Fetch(FetchMode.SELECT)
    public Container getBackpackContainer() {
        return backpackContainer;
    }
}

结果:

User(
    uid=2,
    name=admin,
    ....,

    container=Container(
        id=1,

        items=[
            Item(...),
            Item(...),
            Item(...),
            Item(...)
        ],

        backpacks=[
            Backpack(
                container=1,

                backpackContainer=Container(
                    id=3,
                    items=null, /* Problem! Shouldn't be empty array [] at least or array with items? */
                    backpacks=null /* Problem! Shouldn't be empty array [] at least or array with backpacks? */
                )
            )
        ]
    )
)

正如我注释的结果,嵌套字段项目和背包为空,这表明存在巨大问题。 Hibernate 倾向于使用空集而不是空集,我也不想到处添加空检查器。

什么会导致这个问题?

此外,这个层次结构不是无限深的,用户的容器可以有任意多个背包,但这些背包可能不包含另一个背包。

唯一合乎逻辑的解释是,您正在同一持久性上下文(会话)中读取 User 图,您在其中保存了一个新的(瞬态)Container 实例,其中包含已分配的空值之后加载和组装 User 图时参考 backpackContainer

Hibernate 在保存实例时不会填充关联,但它会在从数据库加载实例时填充关联,因此您使用空值创建它并且它在持久性上下文中仍然如此。当您之后阅读 User 图时,Hibernate 会重用持久性上下文中当前存在的所有内容,包括它分配给 backpackContainer 字段的 Container 实例。

所以,你有两个选择:

  • 如果您确实打算在同一持久性上下文中使用双向关系的双方(更简洁的方法);
  • 或者在读取 User 之前刷新并清除持久性上下文(如果您希望所有事情都发生在同一个事务中):

    entityManager.flush();
    entityManager.clear();