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

JPA场景下如何通过@EmbeddableId在ArrayList中查找关联实体对象

问题根因

  • 第一:Department类中employees集合的@OneToMany注解默认使用懒加载策略,你没有显式配置主动加载的话,调用deleteEmployee方法时集合大概率是未初始化的空代理对象,自然找不到目标关联记录
  • 第二:异常类型不符合场景,找不到员工关联记录却抛出部门不存在的异常,会误导后续问题排查
  • 第三:存在潜在的多记录匹配问题,如果同一个员工在该部门有多条历史任职记录,仅用部门编号和员工编号匹配会命中多条,通常我们需要额外过滤当前在职(toDate为null)的记录
  • 第四:DepartmentEmployeeId实现了Serializable接口但没有显式声明serialVersionUID,JPA序列化/反序列化复合主键时可能出现异常,导致equals匹配失败

修复方案

方案1:调整内存过滤逻辑(适合集合数据量小的场景)

首先补全DepartmentEmployeeId的序列化ID:

@Embeddable
public class DepartmentEmployeeId implements Serializable {
    // 新增序列化ID
    private static final long serialVersionUID = 1L;

    // 原有代码保持不变
}

然后修改Department类的employees属性注解,开启主动加载:

@JsonIgnore
@OneToMany(cascade = CascadeType.ALL, mappedBy = "department", orphanRemoval = true, fetch = FetchType.EAGER)
private List<DepartmentEmployee> employees = new ArrayList<>();

最后修改deleteEmployee方法:

public void deleteEmployee(Long empNo, LocalDate toDate) {
    DepartmentEmployeeId targetId = new DepartmentEmployeeId(this.deptNo, empNo);
    this.employees.stream()
            // 额外过滤当前在职的记录,避免匹配到历史任职记录
            .filter(item -> targetId.equals(item.getId()) && item.getToDate() == null)
            .findAny()
            // 替换为符合场景的异常,也可以自定义员工关联不存在的异常
            .orElseThrow(() -> new IllegalArgumentException("该部门下未找到对应在职员工:" + empNo))
            .setToDate(toDate);
}

方案2:直接通过JPA查询修改(更推荐,适合大数据量场景)

不需要加载整个employees集合,直接通过JPQL语句修改目标记录,性能更高,也不需要处理懒加载问题,只需在DepartmentRepository中新增自定义修改方法即可:

@Modifying
@Query("update DepartmentEmployee de set de.toDate = :toDate where de.id.deptNo = :deptNo and de.id.empNo = :empNo and de.toDate is null")
int updateEmployeeQuitDate(String deptNo, Long empNo, LocalDate toDate);

业务层直接调用该方法执行更新即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 13:24:03