0

我有 3 个实体 A、B 和 C。

  • A 包含一个一对一链接的 B 实体
  • A 包含 C 实体的一对多链接列表
  • B 包含 C 实体的一对多链接列表

数据库方面有 5 个表。对应实体的 3 个表和 2 个单独的链接表,一个包含 A 和 C 之间的链接 (A_to_C),另一个包含 B 和 C 之间的链接 (B_to_C)。在我的存储库中,我试图从特定的 A 记录中检索所有 C 实体,这意味着来自 A 本身的 C 实体和通过 B 链接的 C 实体。

在传统的 SQL 中,这可以使用类似的方法来完成:

select C.*
from A
left join A_to_C on A_to_C.A_ID = A.ID
left join B_to_C on B_to_C.B_ID = A.B_ID
inner join C on C.ID = A_to_C.C_ID OR C.ID = B_to_C.C_ID
where A.ID = '1';

或(从 C 开始)

select C.*
from C
left join A_to_C on A_to_C.C_ID = C.ID
left join B_to_C on B_to_C.C_ID = C.ID
inner join A on A.B_ID = B_to_C.B_ID OR
                A.ID = A_to_C.A_ID
where A.ID = '1';

在这些 SQL 示例中,没有指向 B 表的链接,因为 A 包含 B 的 ID,而且它也是 B_to_C 中使用的 ID,所以我真的不需要它。我也知道这些并不完全相同,但是当我只对 C 感兴趣时,它们会产生相同的结果。

不过,我真的在为如何在 CriteriaBuilder (最好)或 JPQL 中做到这一点而苦苦挣扎。我对 jpa 还是比较陌生,所以我希望这里有人可以帮助我。

4

1 回答 1

2

I believe that, to even have a chance of succeeding with vanilla JPQL, you would need to convert the association to a bidirectional one (or a unidirectional many-to-one) by adding the @ManyToOne side. You could then start the query from C. The @OneToMany side, should you want to retain it, becomes the inverse side of the association in such a scenario, though:

@Entity
public class C {

    @ManyToOne
    @JoinTable
    private B b;

    @ManyToOne
    @JoinTable
    private A a;
}

@Entity
public class B {

    @ManyToOne
    @JoinTable
    private A a;

    @OneToMany(mappedBy = "b")
    private List<C> cs;
}

@Entity
public class A {

    @OneToMany(mappedBy = "a")
    private List<B> bs;


    @OneToMany(mappedBy = "a")
    private List<C> cs;
}

Once you do that, the JPQL query becomes sth like:

SELECT c FROM C c
LEFT JOIN c.a a
LEFT JOIN c.b b
LEFT JOIN b.a a2
WHERE a.id = :id OR a2.id = :id

If you're not OK with making the 'one' side of the association the inverse side, then you're out of luck. The easiest solution is to use a native query.

Eclipselink JPQL Extensions include an ON clause, so perhaps you could combine ON with MEMBER OF:

SELECT c FROM C c
LEFT JOIN A a ON c MEMBER OF a.cs
LEFT JOIN B b ON c MEMBER OF b.cs
LEFT JOIN A a2 ON b MEMBER OF a2.cs
WHERE a.id = :id OR a2.id = :id

I highly doubt it will work, though, and even if it does, I'd be wary of the generated SQL as it might be suboptimal.

于 2020-10-01T19:03:37.917 回答