【问题标题】:Spring boot JPA how to query a @OneToMany relationship given one object in the many relationshipSpring boot JPA如何查询@OneToMany关系给定一个对象的多关系
【发布时间】:2021-04-09 17:00:03
【问题描述】:

我已经看到了一些相关的问题,但我似乎无法为我正在尝试做的事情找到正确的答案。 我有两张表 Jobs 和 Workers,一个job可以有很多workers,简化实体

@Entity
@Table(name = "jobs")
data class Job(
    @Id
    @Type(type = "pg-uuid")
    val id: UUID = UUID.randomUUID()
) {
    @ManyToOne
    var office: Office? = null

    @OneToMany(targetEntity = Worker::class)
    var requests: MutableList<Worker> = mutableListOf()
}

我希望能够获取特定工作人员的工作列表

我已经尝试了一些原生查询,但现在尝试只通过 namedMethods 来完成,老实说,我想这里的任何工作似乎都应该在我的工作存储库中工作

@Repository
interface JobsRepo : CrudRepository<Job, UUID> {

    @Query("SELECT j FROM Job j WHERE id = ?1")
    fun findJobById(id: UUID): Job?

    @Query("SELECT j FROM Job j WHERE office_id = ?1")
    fun findJobsByOffice(id: UUID): List<Job>?

    @Modifying
    @Transactional
    @Query("UPDATE jobs SET job_status = 4 WHERE job_status = 1 AND start_time < ?1", nativeQuery = true)
    fun expireJobs(date: Date)

    fun findByRequests_Worker(worker: Worker): List<Job>?

}

我不太确定如何查询数组属性

requests

在一名工人的投入下。我也尝试查询工作人员的 UUID,因为那是连接表中的内容

JPA 创建一个包含两个外键的连接表

jobs_requests

和列

job_id UUID
requests_id UUID

【问题讨论】:

  • 您能否向我们展示您的实体及其关系的数据库映射?
  • 你的数据库脚本呢?
  • 没有数据库脚本 hiberante 正在做这一切

标签: spring spring-boot spring-data-jpa spring-data


【解决方案1】:

您提到一个 Job 可以有多个 worker,并且您还提到您想要获取特定 worker 的作业列表。所以这听起来像是多对多关系而不是单对多关系。

对于多对多关系,连接表是不可避免的。您需要在两个实体上指定 @ManyToMany 注释,然后您可以使用 WorkerRepository 查询工作人员,然后获取该工作人员的工作列表,您只需通过 worker.getJobs() 访问即可。

以下是多对多关系的设置,希望对你有帮助:

@Entity
@Table(name = "jobs")
data class Job (
    @ManyToMany
    @get:ManyToMany
    @get:JoinTable(
            name = "worker_job",
            joinColumns = [JoinColumn(name = "job_id")],
            inverseJoinColumns = [JoinColumn(name = "worker_id")]
    )
    val worker: Set<Worker> = HashSet()

)
@Entity
@Table(name = "worker")
data class Worker (
    @ManyToMany
    @get:ManyToMany
    @get:JoinTable(
            name = "worker_job",
            joinColumns = [JoinColumn(name = "worker_id")],
            inverseJoinColumns = [JoinColumn(name = "job_id")]
    )
     val jobs: Set<Jobs> = HashSet()
)

【讨论】:

  • manytomany 似乎已经让它工作了,但这并没有多大意义,一份工作可以有很多工人,但仅限于那份工作。另一方面,是的,工人会有很多工作,也许我错过了多对多的想法。实体映射对我来说是新的,但考虑到你添加的额外 sql 为什么它会是多对多。一份工作有一系列工人,OneToMany 也许我想错了。另外,我没有将工作对象定义为双向的,这可能是个问题。最后一个问题,集合、列表或可变列表是否会影响表格的构建方式。
  • '一个工作可以有多个工人' - 这意味着Job -&gt; Worker 是一个对多的关联。 'workers will have many jobs' - 这意味着Worker -&gt; Job 是一个多对多关联。将它们加在一起,您将获得多对多关联。例如,如果一个工人只能有一份工作,这将是一个一对多的关联
  • @crizzis 很好地解释了为什么它是多对多关系。
  • 至于list和set的区别,不用担心set中的重复项,为什么list允许重复元素。对于可变列表,它是一个您可以读取和修改的列表,其中不可变列表只允许您阅读。与集合和可变/不可变集合类似。上面的代码sn-p使用了HashSet,它是ImmutableSet的一个实现。
【解决方案2】:

还值得注意的是,对于所有实际用途,您应该尽量避免显式的 ManyToMany 注释。您应该创建一个新的实体/表,其中将包含 Job 和 Worker 的字段,它们都与各自实体的 ManyToOne 关联。

你应该避免显式的 ManyToMany 的原因是,比如说当有一个特定的工作时,例如 JavaDev,并且在给定的工作上有 1000 个 Workers。在某一时刻,您有一个 JavaDev 实体,并且您想要获取所有年龄在 20 到 25 岁之间的工人。为此,需要迭代 Workers 列表这是 JavaDev 实体的一部分并将它们过滤掉。发生这种情况时有两种情况:

  1. Workers 列表是一个惰性关联,当您尝试访问它时,hibernate 会向数据库发送 1000(n+1 个问题)查询。
  2. Workers 列表是一个急切的关联,当您尝试获取 JavaDev 实体时,hibernate 会向数据库发送相同数量的查询。

因此,您的执行时间会增加,因为数据库本身会产生不必要的负载。而在大型项目中,这将变得更加复杂。

如果您创建自己的 manytomany(job_workers for ex.) 表以及随附的存储库和服务,所有这些都可以避免,您将能够更有效地查询数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-30
    • 2016-02-02
    • 1970-01-01
    • 2017-10-28
    • 2022-09-25
    • 2019-01-24
    • 2014-04-08
    • 1970-01-01
    相关资源
    最近更新 更多