如何在查询中包含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
相关产品推荐
相关产品推荐

