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 【问题描述】:我有两个实体,Menu
和 MenuItem
,如下面的源代码所示。我正在尝试从数据库中获取包含所有子实体的菜单,但 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)
Hibernate-Validator 接口参数校验 | 嵌套参数校验