Hibernate 不包含与另一个实体列表中的实体相同类型的子实体

Posted

技术标签:

【中文标题】Hibernate 不包含与另一个实体列表中的实体相同类型的子实体【英文标题】:Hibernate do not include child entities of same type as entity in list of another entity 【发布时间】:2020-05-26 19:03:45 【问题描述】:

我有两个实体,MenuMenuItem,如下面的源代码所示。我正在尝试从数据库中获取包含所有子实体的菜单,但 Hibernate 还在 Menu 实体的 nodes 列表中插入了 MenuItem 的子实体。

菜单.java

[...]

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "menu", cascade = CascadeType.ALL, orphanRemoval = true)
    @OrderBy("order ASC")
    private List<MenuItem> nodes = new ArrayList<MenuItem>();
[...]

MenuItem.java

[...]

    @ManyToOne
    @OnDelete(action = OnDeleteAction.CASCADE)
    @JoinColumn(name = "parentId")
    private MenuItem parentItem;

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "parentItem", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<MenuItem> children = new ArrayList<MenuItem>();

    @ManyToOne(optional = false)
    @JoinColumn(name = "menuId")
    private Menu menu;
[...]

作为提示:我知道您不应该将 FetchType.EAGER 用于集合,但由于我需要集合的所有元素,因此在加载菜单时加载它们很有用。如果没有列表,菜单将无法使用。

【问题讨论】:

您可以添加“图片”以如何查看您的数据库吗?这对回答您的问题非常有帮助,因为在您的问题中,您在一个类中建立了 ManyToOne 关系。 【参考方案1】:

只有应该是 Menu 的直接后代的 MenuItem 才应该设置 menu 字段,否则由于 mappedBy = "menu",它们都将被提取到 nodes 集合中。

顺便说一句,就您的 EAGER 提取类型的用例而言,您通常不应使用 EAGER 提取,而不仅仅是在集合上。 This is a good read about the topic.

【讨论】:

好的,如何使用 HQL 加载所有集合,尤其是当 MenuItem 有子 MenuItems,然后它们还有一个 MenuItems 集合,就像一棵树? HQL 不支持递归查询,因此除非您的数据库支持递归查询并且您愿意使用本机查询(或创建视图?),否则您将需要 MenuItem 上的附加字段来引用 @ 987654327@ 并将其设置在每个 MenuItem 上。例如,menu 字段将仅为菜单的直接后代(菜单的第一级)设置,root 字段将为所有后代设置。【参考方案2】:

CascadeType.ALL 会将所有 EntityManager 操作传播(级联)到相关实体。

尝试从关系中删除cascade = CascadeType.ALL

默认情况下,没有操作级联。

【讨论】:

以上是关于Hibernate 不包含与另一个实体列表中的实体相同类型的子实体的主要内容,如果未能解决你的问题,请参考以下文章

如何使用本机 SQL 在 Hibernate 中获取仅包含选定列的表实体列表?

实体列表的 CriteriaBuilder 和 isMember (Hibernate)

JPQL查询-实体包含一个Longs列表

Hibernate-Validator 接口参数校验 | 嵌套参数校验

Hibernate-Validator 接口参数校验 | 嵌套参数校验

JAVAEE学习笔记hibernate02:实体规则对象状态缓存事务批量查询和实现客户列表显示