【问题标题】:JPA Criteria API checking if an association collection is a subset of another collectionJPA Criteria API 检查关联集合是否是另一个集合的子集
【发布时间】:2015-07-10 16:04:24
【问题描述】:

我有 2 张桌子:joblanguage。这两个表之间的关系是 m:n,这意味着一个工作可能需要多种语言,而一种语言可能需要多种工作。所以我必须创建一个名为job_language 的第三个表来表示这种关系,它只包含两列job_id(它是一个整数)和language_code(例如'eng' 用于英语或'jap' 用于日语, ETC。)。我使用的数据库是 MySQL。

现在我必须使用 Spring Data JPA 创建一个 REST 服务,以获取所有需要一组语言的作业,这些语言是来自用户输入的另一组语言的子集。例如,假设我有 3 个工作,其值在表 job_language 中,如下所示:

--------------------------
| job_id | language_code |
--------------------------
| 1      | 'eng'         |
--------------------------
| 2      | 'eng'         |
--------------------------
| 2      | 'vie'         |
--------------------------
| 3      | 'jap'         |
--------------------------
| 3      | 'eng'         |
--------------------------
| 3      | 'vie'         |
--------------------------

现在用户想要查找需要('eng', 'vie') 的工作(这是根据用户输入创建的language_code 列表),查询应返回两个工作:job_id = 1 的工作和job_id = 2 的工作。

这些是我的实体类:

@Entity
public class Job {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @ManyToMany
    @JoinTable(name = "job_language", 
        joinColumns = { @JoinColumn(name = "job_id", nullable = false) },
        inverseJoinColumns = { @JoinColumn(name = "language_code", nullable = false) })
    private List<Language> languages;

    // getters and setters here...
}

@Entity
public class Language { 
    @Id
    @Column(columnDefinition = "char", length = 3)
    private String code;

    @Column(length = 100)
    private String name;

    // getters and setters...
}

我有一个 MySQL 查询可以做到这一点,但由于 JPQL 不允许左连接两个不相关的表,我找不到使用 JPA Criteria API 的解决方案。有什么建议么?

这是我的工作查询:

select jl1.job_id
from job_language jl1 left join job_language jl2 on jl1.job_id = jl2.job_id and jl1.language_code = jl2.language_code and jl2.language_code in ('eng', 'vie')
group by jl1.job_id
having count(jl1.language_code) = count(jl2.language_code);

【问题讨论】:

  • 请看看这是否有帮助:stackoverflow.com/questions/18488351/…
  • @MatiasCaamaño 不,它不会有帮助,这个问题是关于检查一个字符串是否包含在另一个字符串中,但我的问题是检查一个关联集合是否是另一个集合的子集,也许我是我的问题不清楚,让我编辑它,请稍后再看。

标签: java mysql hibernate spring-data-jpa


【解决方案1】:

您可以将查询用作带有 Spring Data 存储库的本机 SQL 查询。举个例子:

public interface JobRepository extends JobRepository<Job, Long> {
  @Query(nativeQuery = true
      , value = "SELECT "
              + "  * "
              + "FROM"
              + "  job "
              + "WHERE "
              + "  id IN "
              + "  ( "
              + "  SELECT "
              + "    jl1.job_id "
              + "  FROM "
              + "    job_language jl1 "
              + "  LEFT JOIN "
              + "    job_language jl2 "
              + "  ON "
              + "    jl1.job_id = jl2.job_id "
              + "  AND jl1.language_code = jl2.language_code "
              + "  AND jl2.language_code IN ?1 "
              + "  GROUP BY "
              + "    jl1.job_id "
              + "  HAVING "
              + "    COUNT(jl1.language_code) = COUNT(jl2.language_code) "
              + "  )")
  List<Job> findAllByLanguageCodes(String... languageCodes);
}

使用原生查询的唯一标准是 Spring Data 应该能够将原生查询的返回值转换为带注释的方法的返回类型。我们通过在查询顶部放置 SELECT * FROM job 来利用这一点,这允许 Spring Data JPA 很好地处理结果,因为 job 映射到 JPA 实体(即使 job_location 确实驱动查询, 不是)。

查看工作示例here

【讨论】:

  • 谢谢。 Spring Data JPA 不允许使用本机查询进行分页,这就是我放弃使用本机查询的原因,但现在我知道 MySQL 中有 'limit' 和 'offset' 关键字,本机查询是我的问题的解决方案.谢谢你建议我使用原生查询,所以我可以再看一遍:)。
  • 分页查询使用LIMITOFFSET,因此您走在正确的轨道上。
猜你喜欢
  • 2021-04-05
  • 2021-12-13
  • 1970-01-01
  • 2013-12-02
  • 2020-11-16
  • 1970-01-01
  • 2022-01-04
  • 2013-04-20
相关资源
最近更新 更多