【问题标题】:Hibernate left join fetch on many returns duplicitiesHibernate left join fetch 对许多返回重复
【发布时间】:2021-10-19 10:40:58
【问题描述】:

我有一个问题,我通过 Spring 数据使用 Hibernate,并且我有这个数据模型(模型要大得多,但这是导致问题的部分)。

假设我们有Entity AEntity B。 两个实体之间的关系是多对多

我正在尝试使用 B 记录 fetched 获取 A 记录(以防止延迟加载)。

模型是这样连接的

在实体 A 上:

@ManyToMany(mappedBy = "items")
private List<BEntity> bs = new ArrayList<>();

关于实体 B

@ManyToMany
@JoinTable(
        name = "a_b",
        joinColumns = { @JoinColumn(name = "b_id", referencedColumnName = "id") },
        inverseJoinColumns = { @JoinColumn(name = "a_id", referencedColumnName = "id") }
)
private Collection<AEntity> as = new ArrayList<>();

所以它是典型的 M:N 关系。我正在尝试检索 A 数据,如下所示

@Query("SELECT a FROM AEntity a " +
        "   LEFT JOIN FETCH a.bs" +
        "WHERE a.id IN (:aIds)")
List<AEntity> findX(@NonNull @Param("aIds") Collection<Long> aIds);

生成的 SQL 类似于

select X -- select fields omitted for simplicity
from item itembo0_
         left outer join a_b ab on a.id = ab.a_id
         left outer join b b on ab.b_id = b.id
where a.id in (...)

这是我所期望的。 SQL 将导致重复(我也期望这会导致可能有许多 B 记录,每个记录都有一个结果行)。但最后,hibernate 不会将所有这些行合并到一个带有提取的 B 字段的 A 实体中

例如,当我将 5 个 IDS 传递到“in”条件时,我得到了 10 个 A 记录。 每一个都有2个B记录链接!这就是奇怪的部分

有没有人可以告诉我为什么hibernate不通过A.id标识符合并这些SQL结果并进行重复?是不是因为我要的是 List 而不是 Set?

【问题讨论】:

  • 您是否实现了正确的equalshashCode?见vladmihalcea.com/…。此外,您可能想在查询中使用SELECT DISTINCT a ...

标签: java sql spring hibernate spring-data


【解决方案1】:

在查询中使用“DISTINCT”关键字应该足以避免重复:

@Query("SELECT DISTINCT a FROM AEntity a " +
        "   LEFT JOIN FETCH a.bs" +
        "WHERE a.id IN (:aIds)")
List<AEntity> findX(@NonNull @Param("aIds") Collection<Long> aIds);

我不知道您存储什么样的数据,但正如您所提到的,也许更好的解决方案是使用 Set 而不是 List。

【讨论】:

  • 嗨,DISTINCT 有效,但我想了解为什么 Hibernate 不能像 1:M 关系那样处理这些子记录,具有 1:M 关系的 SQL 的结果也有重复但是Hibernate 正确地将所有行与 FROM 实体的主键合并在一起并创建实体对象。
  • 不幸的是,这个问题在 Hibernate 方面。官方文档说:“使用急切获取集合的查询通常返回根对象的重复项,但它们的集合已初始化。您可以通过 Set 过滤这些重复项。” link
  • 默认的 ManyToMany Fetch 是 LAZY。返回 SET(或使用 distinct)工作正常,但它仍然是一种解决方法。我希望 Hibernate 能够 JOIN FETCH 没有重复的许多孩子(就像 1:M 的情况一样)
猜你喜欢
  • 2011-10-13
  • 1970-01-01
  • 2018-12-15
  • 2015-01-30
  • 1970-01-01
  • 2021-09-12
  • 2013-11-28
  • 1970-01-01
  • 2021-11-26
相关资源
最近更新 更多