JPQL 多对多带 in 子句

JPQL Many to Many with in Clause

我想知道是否有办法将我的本机查询转换为 JPQL 查询。

查询

public interface GraphJobRepository extends JpaRepository<GraphJob, Long> {

    @Query(value = "Select * From graph_job where id in (\n" +
            "    SELECT distinct g.graph_job_id\n" +
            "    FROM graph_job_role g\n" +
            "             INNER JOIN clover_role r ON g.clover_role_id = r.role_id\n" +
            "    WHERE r.role_name in (:roles))",
            nativeQuery = true)
    List<GraphJob> findGraphJobsByRoles(@Param("roles") List<String> roles);

}

三叶草角色

@Data
@Entity
public class CloverRole {

    @Id
    @Column(name = "role_id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String roleName;
}

图形作业

@Entity
public class GraphJob {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @JoinTable(name = "graph_job_role", joinColumns = {
            @JoinColumn(name = "graph_job_id")}, inverseJoinColumns = {
            @JoinColumn(name = "clover_role_id")})
    @ManyToMany
    private Collection<CloverRole> roles;

}

我尝试过的任何方法都没有奏效,我确定如果我要添加 join table 实体我可以让它工作,但我想知道是否有人知道如何在没有实际上创建那个实体。

您可以尝试使用 member of 运算符、交叉连接和 List<String> 作为参数

@Query("select distinct j from GraphJob j, CloverRole r where r member of j.roles and r.roleName in(:roleNames)")
List<GraphJob> findGraphJobsByRoleNames(@Param("roleNames") List<String> roleNames);

如果您的目标是摆脱嵌入的字符串,您可以使用 FluentJPA 作为纯粹的 Java 解决方案:

(无需更改现有代码)

public interface GraphJobRepository extends JpaRepository<GraphJob, Long>,
                                            EntityManagerSupplier {

    default List<GraphJob> findGraphJobsByRoles(List<String> roles) {

        FluentQuery query = FluentJPA.SQL((GraphJob job) -> {

            List<Long> jobIds = subQuery((CloverRole r,
                                       JoinTable<GraphJob, CloverRole> graphJobRole) -> {

                SELECT(graphJobRole.getJoined().getId());
                FROM(graphJobRole).JOIN(r)
                                  .ON(graphJobRole.inverseJoin(r, GraphJob::getRoles));
                WHERE(roles.contains(r.getRoleName()));
            });

            SELECT(job);
            FROM(job);
            WHERE(jobIds.contains(job.getId()));

        });

        return query.createQuery(getEntityManager(), GraphJob.class).getResultList();
    }
}

产生以下 SQL:

SELECT t0.*
FROM graph_job t0
WHERE (t0.id IN (SELECT t2.graph_job_id
FROM graph_job_role t2  INNER JOIN clover_role t1  ON (t2.clover_role_id = t1.role_id)
WHERE (t1.role_name IN ?1 )) )

FluentJPA先提供classJPA Repository integration and supplies a "virtual" join table.