左连接获取重复

abk*_*drd 0 hibernate jpa lazy-evaluation fetch

我在使用 JPA(Hibernate) 和 LazyFetching 时遇到了一些麻烦

我有一些实体:任务、奖励、合同

关系(都是懒人):

  • Quest One2Many 奖励;任务多对多合约;
  • 合约One2Many奖励;合同多对多任务;
  • 奖励 Many2One 查询;奖励多对一合约;

DB 包含这样的数据:Quest1 有 Reward1、Reward2 和 Contract1、Contract2;

在某些情况下,我需要 Quest 及其奖励和合同,所以我在 JPArepository 中这样做:

@Query("select Q from Quest Q left join fetch Q.rewards left join fetch Q.contracts")
List<Quest> getAllQuestsWithRewardsAndContracts();
Run Code Online (Sandbox Code Playgroud)

问题是我收到了
一个有 4 个(但只有 2 个)奖励(Reward1、Reward2、Reward1、Reward2)和两个合同的任务。
我得到重复的奖励!
我不明白为什么!
如果我这样做:

@Query("select distinct Q from Quest Q left join fetch Q.rewards")
List<Quest> getAllQuestsWithRewardsRew();
Run Code Online (Sandbox Code Playgroud)

我收到一个任务有两个奖励(Reward1,Reward2)

为什么 ?为什么我有重复?

fri*_*ley 5

这就是 Hibernate 工作的本质。它不会删除由 LEFT OUTER JOINS 生成的重复项。您可以明确指定您需要不同的结果

例如,如果您使用标准来获取数据,您可以指定

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
Run Code Online (Sandbox Code Playgroud)

检查获取数据时生成的 SQL。这是一个常见问题解答,它更多地解释了 Hibernate 为何在此处以这种方式行事

同样在第一个查询中,您正在同一 SQL 中加载多个集合(奖励和合同),这可能会导致笛卡尔积。Hibernate 有一个Futures API,它有助于使用比生成笛卡尔积的 SQL 更简单的 SQL 加载多个子集合。(我不确定 Futures 是否可以与 JPA 一起使用)