【问题标题】:Duplicated results in Hibernate OneToMany ListHibernate OneToMany 列表中的重复结果
【发布时间】:2017-10-11 23:42:39
【问题描述】:

我已经用@OneToMany 列表映射了一个 1:N 关系,但是当我访问该列表时,由于 OUTER JOIN 导致结果重复。 这是映射的样子:

@Entity
public class Programmer

    @ElementCollection(fetch=FetchType.EAGER)
    @CollectionTable(name="emails", joinColumns=@JoinColumn(name="id", nullable=false))
    @Column(name="email", nullable=false)
    protected Set<String> emails = new HashSet<String>();

    @OneToMany(mappedBy="programmer", fetch=FetchType.EAGER)
    private List <Game> games = new ArrayList<Game>();

当我使用 prog.getGames() 获取属性时,结果重复了,因为 Hibernate SQL 进行了 OUTER JOIN:

from programmer 
left outer join emails on programmer.id=emails.id 
left outer join game on programmer.id=game.id
where programmer.id=?

如果不将 List 转换为 Set,有什么解决方案吗?我需要使用 prog.getGames() 获取游戏,不能使用自定义 HQL 或 Criteria。

【问题讨论】:

  • 我需要通过使用 Programmer.getGames() 获取游戏的 JUnit 测试,没有 Criteria 怎么办?
  • @WEI_DBA 不认为这是重复的 - 根据他的问题,OP 正在寻找答案而不使用标准。
  • 我对 Hibernate/JPA 不太熟悉,但为什么不能使用 Set 呢?那将是我天真的解决方案,不知道在 Hibernate 中执行此操作的“理想”方式。

标签: java sql hibernate duplicates


【解决方案1】:

虽然使用Set&lt;&gt; 可以从根本上解决您的问题,但我认为这只是获得您所追求的预期结果的创可贴,但在技术上并不能解决根本问题。

您最终应该使用默认的延迟获取策略,因为我认为急切地加载任何关联,尤其是基于集合的关联,是特定于查询的,因此应该在构建特定查询时进行切换并且不受影响作为您的实体映射模型的一部分。

考虑将来您添加新查询但您只对聚合根实体中的属性感兴趣。您的映射模型仍会急切地获取这些关联,您将通过拥有更大的持久性上下文来消耗额外的资源,这意味着更多的内存消耗并为您不打算使用的东西施加不必要的数据库连接。

如果您需要补充多个集合,我建议您考虑改用FetchMode.SUBSELECT

如果我们假设您的查询返回了 10 个实体,则具有 2 个集合的默认惰性策略将发出 21 个查询(1 个用于基本结果集,2 个用于每个加载的实体)。

SUBSELECT 的好处是 Hibernate 实际上只会发出 3 个查询(1 个用于基本结果集,1 个用于每个集合以加载所有实体的所有集合元素)。显然,根据某些查询,将一个带有左连接的查询分成 3 个查询实际上也可以在数据库级别执行得更好。

【讨论】:

  • 延迟选择然后要求一直打开事务
【解决方案2】:

我已经用@Fetch(FetchMode.SUBSELECT) 解决了这个问题

【讨论】:

    猜你喜欢
    • 2018-09-11
    • 1970-01-01
    • 1970-01-01
    • 2014-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多