如何在查询中包含@OneToMany关联映射值,实现两类人员信息查询
实现两类人员信息查询的解决方案
我需要实现两类查询:
A. 获取人员基础信息,示例返回:
{ "id": 186506, "pidm": 324950, "first_name": "Jane" }
B. 获取人员基础信息及其电话号码,示例返回:
{ "id": 186506, "pidm": 324950, "first_name": "Jane", "phones": ["1234567890", "0987654321"] }
目前通过现有映射配置,只能单独获取人员基础信息或电话号码,无法实现两者的组合查询,请问该如何操作?是否可行?
以下是使用的领域实体类:
@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 @OneToMany(mappedBy = "person") @JsonBackReference private List<Telephone> phones List<Telephone> getPhones() { return phones } }
@Entity @Table(name="TELEPHONE") class Telephone implements Serializable { @Id @Column(name="telephone_id") Long id @Column(name="person_pidm") String pidm @Column(name="telephone_phone_number") String phone_number @ManyToOne @JoinColumn(name="sprtele_pidm", referencedColumnName = "spriden_pidm") private SpridenDetail person; }
问题分析与解决方案
完全可行,核心是先修正实体类的关联错误,再通过查询控制或DTO实现不同返回结构:
1. 修正实体类关联问题
现有代码里Telephone类的@ManyToOne关联的是SpridenDetail,但Person实体才是对应的关联类,这会导致JPA无法正确建立关联,同时Person类的@JsonBackReference会让序列化时忽略phones字段,先改这两处:
- 修正
Telephone类的关联:
@Entity @Table(name="TELEPHONE") class Telephone implements Serializable { @Id @Column(name="telephone_id") Long id @Column(name="person_pidm") String pidm @Column(name="telephone_phone_number") String phone_number // 把关联实体改成Person,同时修正JoinColumn字段匹配Person表的pidm列 @ManyToOne @JoinColumn(name="person_pidm", referencedColumnName = "person_pidm") private Person person; }
- 调整
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 // 替换@JsonBackReference为@JsonManagedReference(避免双向序列化循环),或者直接去掉 @OneToMany(mappedBy = "person") @JsonManagedReference private List<Telephone> phones List<Telephone> getPhones() { return phones } }
2. 实现两类查询
查询A:仅获取人员基础信息
用DTO(数据传输对象)来精准控制返回字段,避免返回多余数据:
// 定义基础信息DTO class PersonBasicInfo { private Long id; private Long pidm; private String firstName; public PersonBasicInfo(Long id, Long pidm, String firstName) { this.id = id; this.pidm = pidm; this.firstName = firstName; } // getter方法 } // 在Repository中写投影查询 @Repository public interface PersonRepository extends JpaRepository<Person, Long> { @Query("SELECT new com.example.dto.PersonBasicInfo(p.id, p.pidm, p.first_name) FROM Person p WHERE p.id = :id") PersonBasicInfo findBasicInfoById(@Param("id") Long id); }
查询B:获取基础信息+电话号码
通过JOIN FETCH主动关联查询电话号码,再用DTO把电话号码提取成字符串数组:
// 定义带电话号码的DTO class PersonWithPhones { private Long id; private Long pidm; private String firstName; private List<String> phones; public PersonWithPhones(Person person) { this.id = person.getId(); this.pidm = person.getPidm(); this.firstName = person.getFirst_name(); // 从Telephone列表中提取号码 this.phones = person.getPhones().stream() .map(Telephone::getPhone_number) .collect(Collectors.toList()); } // getter方法 } // 在Repository中关联查询 @Repository public interface PersonRepository extends JpaRepository<Person, Long> { @Query("SELECT p FROM Person p JOIN FETCH p.phones WHERE p.id = :id") Person findWithPhonesById(@Param("id") Long id); }
调用时把查询到的Person实例传入PersonWithPhones构造器,返回的DTO序列化后就和示例JSON结构一致。
内容的提问来源于stack exchange,提问作者santiago
相关产品推荐
相关产品推荐

