JPQL многие ко многим в статье - PullRequest
0 голосов
/ 24 октября 2019

Мне интересно, есть ли способ конвертировать мой собственный запрос в запрос 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);

}

CloverRole

@Data
@Entity
public class CloverRole {

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

    private String roleName;
}

GraphJob

@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;

}

Ничего из того, что я пробовал, не сработало, я уверен, что еслиЯ должен был добавить сущность объединяющей таблицы, я мог бы заставить ее работать, но мне интересно, знает ли кто-нибудь, как это сделать без фактического создания этой сущности.

Ответы [ 2 ]

2 голосов
/ 24 октября 2019

Вы можете попробовать member of оператор. Параметр должен быть List<CloverRole>

@Query("from GraphJob j where :roles member of j.roles")
List<GraphJob> findGraphJobsByRoles(@Param("roles") List<CloverRole> roles);

Или использовать перекрестное соединение и 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);
0 голосов
/ 25 октября 2019

Если ваша цель - избавиться от встроенной строки, вы можете использовать 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 предоставляет первый класс Интеграция с репозиторием JPA и предоставляет "виртуальную" таблицу соединений .

...