JPQL 从一对一关系查询到 select 实体,其中它的相关字段具有匹配特定条件的字段

JPQL Query to select entity from one-to-one relationship where it's relative has a field matching a certain condition

我有三个实体:EntityA 映射到 table_aEntityB 映射到 table_bCatalog 映射到 catalog。在数据库中,table_bcatalogb_catalog_xref之间存在多对多table。 EntityB 有一个字段:Long aId 和一个字段:List<Catalog> catalogs。 Catalog 实体有一个字段:String name。给定 EntityB 的 ID 列表和表示目录名称的字符串,我需要检索所有出现的 EntityA,其 ID 与 EntityB 的 aId 匹配,并且给定的目录名称与 EntityB 的目录之一匹配.

我已经通过常规 SQL 成功获取了正确的数据,但我很难在 JPQL 中重新创建查询。这是 SQL 查询:

SQL:

SELECT
   *
FROM
    table_a a
WHERE
    a.table_a_id in (
    SELECT
        b.table_a_id
    FROM
        table_b b
        INNER JOIN b_catalog_xref bcx ON bcx.table_b_id = b.table_b_id
        INNER JOIN catalog c ON c.catalog_id = bcx.catalog_id
    WHERE
        c.catalog_name = 'Example Catalog Name'
);

Java:

@Entity
@Table(name = "table_a")
public class EntityA {

    @Id
    @Column(name = "table_a_id")
    private Long aId;

    ...
}
@Entity
@Table(name = "table_b")
public class EntityA {

    @Id
    @Column(name = "table_b_id")
    private Long bId;

    @Column(name = "table_a_id")
    private Long aId;

    @OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.DETACH})
    @JoinTable(name = "b_catalog_xref",
               joinColumns = {@JoinColumn(name = "table_b_id")},
               inverseJoinColumns = {@JoinColumn(name = "catalog_id")})
    @Fetch(FetchMode.SELECT)
    @OrderBy("name ASC")
    List<Catalog> catalogs

    ...
}

@Entity
@Table(name = "catalog")
public class Catalog {

    @Id
    @Column(name = "catalog_id")
    private Long catalogId;

    @Column(name = "catalog_name")
    private String name;

    ...
}

是的,你可以使用类似

的东西
TypedQuery<TableA> q = entityManager.createQuery
            ("Select a from TableA a where a.aId in(Select b.aId from TableB b " +
                    "join b.catalogs c where c.name=:name)", TableA.class);
q.setParameter("name", "some2");

我建议您考虑在 table 的 A 和 B 之间创建关系,而不是将 table A 的密钥复制到 table B

@Entity
@Table(name = "table_b")
public class EntityB {
...
//    @Column(name = "table_a_id")
//    private Long aId;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "table_a_id")
    private TableA tableA;
...
}

那么 JPQL 将如下所示:

TypedQuery<TableA> q = entityManager.createQuery
                ("Select distinct b.tableA from TableB b join b.catalogs c " +
                        "where c.name=:name", TableA.class);
q.setParameter("name", "some2");

注意关键字distinct,它会删除结果列表中的所有重复项。

除非绝对必要,否则不要使用 FetchType.EAGER,请使用 FetchType.LAZY