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

如何在查询中包含@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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 15:25:15