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

时间:2017-06-16 19:31:19

标签: java hibernate jpa fetch

我想热切地填充我的对象层次结构。问题是,在某些时候,Hibernate会停止提取;它使关系字段(列表)无人居住。

层次结构是(某些代码被省略,就像id,getters一样,这部分看起来很好,希望如此):

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倾向于使用空集而不是空值,我也不想在任何地方添加空检查器。

什么可能导致这个问题?

此外,这个层次结构不是无限深,用户的容器可能有它想要的背包,但那些背包可能不包含其他背包。

1 个答案:

答案 0 :(得分:1)

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

在保存实例时,Hibernate不会填充关联,但是在从db加载实例时会执行此操作,因此您使用null创建了它,并且它在持久性上下文中仍然存在。当您之后阅读User图表时,Hibernate会重用持久化上下文中当前存在的所有内容,包括它分配给Container字段的backpackContainer实例。

所以,你有两个选择:

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

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