You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在查询中包含OneToMany关联字段的所有值

问题描述

我有以下两个实体类:

Person 实体类

@Entity
@Table(name="PERSON")
class Person implements Serializable {

    @Id
    @Column(name="person_id")
    Long id

    @Column(name="person_pidm")
    Long pidm

    @Column(name="person_first_name")
    String first_name

    @Column(name="person_last_name")
    String last_name

    @OneToMany(mappedBy="pidm")
    private List<Telephone> phones

    List<Telephone> getPhones() {
        return phones
    }
}

Telephone 实体类

@Entity
@Table(name="TELEPHONE")
class Telephone implements Serializable {

    @Id
    @Column(name="telephone_id")
    Long id

    @Column(name="telephone_phone_number")
    String phone_number

    @ManyToOne
    @JoinColumn(name="telephone_pidm", referencedColumnName="person_pidm")
    private Person pidm;

}

目前我用以下查询获取Person对象,但返回结果里没有phones字段:

def result = Person.executeQuery(
    "SELECT s " +
    "FROM Person " +
    "WHERE s.pidm = :pidm",
    [pidm: pidm]
)

返回结果示例:

{
    "id": 186506,
    "first_name": "JANE",
    "last_name": "DOE",
    "pidm": 324950
}

我希望在需要时,查询结果能包含phones字段,得到如下格式的JSON:

{
    "id": 186506,
    "phones": [
        {
            "id": 329815,
            "phone_number": "1234567890"
        },
        {
            "id": 329816,
            "phone_number": "0987654321"
        }
    ],
    "first_name": "JANE",
    "last_name": "DOE",
    "pidm": 324950
}

请问如何编写查询语句实现这个需求?

解决方案

方法1:使用JOIN FETCH强制关联查询

JPA默认对@OneToMany关联采用懒加载(Lazy Loading),所以默认查询Person时不会主动加载phones列表。可以在JPQL中用JOIN FETCH一次性加载关联数据,避免N+1查询问题:

def result = Person.executeQuery(
    "SELECT s " +
    "FROM Person s " +
    "JOIN FETCH s.phones " +
    "WHERE s.pidm = :pidm",
    [pidm: pidm]
)

如果一个Person对应多个Telephone,JOIN FETCH可能会返回重复的Person对象,此时可以用DISTINCT去重:

def result = Person.executeQuery(
    "SELECT DISTINCT s " +
    "FROM Person s " +
    "JOIN FETCH s.phones " +
    "WHERE s.pidm = :pidm",
    [pidm: pidm]
)

方法2:修改关联的FetchType为EAGER(按需场景不推荐)

如果希望每次查询Person都自动加载phones,可以修改@OneToMany的fetch属性为FetchType.EAGER:

@OneToMany(mappedBy="pidm", fetch = FetchType.EAGER)
private List<Telephone> phones

但这种方法不适合按需加载的场景,会导致每次查询Person都强制加载phones,可能影响性能,只建议在确定每次都需要关联数据时使用。

方法3:事务内触发懒加载(简单但低效)

如果保持懒加载,但需要在获取Person后主动加载phones,可以在Service层调用person.getPhones().size()(或遍历列表)触发懒加载,前提是当前仍在事务上下文内:

def person = Person.findByPidm(pidm)
person.getPhones().size() // 触发懒加载,加载关联的phones

不过这种方法会产生额外的SQL查询,性能不如JOIN FETCH高效。

内容的提问来源于stack exchange,提问作者santiago

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 14:20:37