循环两个列表创建EmployeeProject时避免重复或值覆盖的方法
解决EmployeeProject关联保存的循环问题
问题根源分析
你遇到的两个问题本质是两个常见错误:
- 所有工时都是最后一个值:循环中复用了同一个
EmployeeProject对象,后续赋值覆盖了之前的所有实例数据 - 生成重复数据(9条):对Project列表和Double列表做了嵌套循环,产生笛卡尔积(3×3=9),而非一一对应关联
一、修正Thymeleaf表单参数绑定
确保项目与对应工时通过索引绑定,提交后能按顺序匹配:
<!-- 遍历Project列表,为每个项目绑定对应工时输入框 --> <div th:each="project, stat : ${projectList}"> <!-- 隐藏字段存项目ID,按索引分组 --> <input type="hidden" th:name="projectIds[__${stat.index}__]" th:value="${project.id}" /> <!-- 工时输入框,与对应项目索引一致 --> <input type="number" th:name="bookedMonths[__${stat.index}__]" step="0.1" placeholder="输入工时" /> </div> <!-- 员工ID隐藏字段 --> <input type="hidden" name="employeeId" th:value="${employee.id}" />
二、Controller正确处理逻辑
按索引一一遍历项目与工时,每次循环新建EmployeeProject实例,避免复用覆盖:
@PostMapping("/save-association") public String saveEmployeeProject(@RequestParam Long employeeId, @RequestParam List<Long> projectIds, @RequestParam List<Double> bookedMonths) { // 获取关联员工 Employee employee = employeeRepo.findById(employeeId).orElseThrow(() -> new RuntimeException("员工不存在")); // 按索引一一匹配项目与工时,避免笛卡尔积 for (int i = 0; i < projectIds.size(); i++) { // 关键:每次循环新建实例,禁止复用 EmployeeProject empProject = new EmployeeProject(); // 设置关联员工 empProject.setEmployee(employee); // 设置对应索引的项目 Project project = projectRepo.findById(projectIds.get(i)).orElseThrow(() -> new RuntimeException("项目不存在")); empProject.setProject(project); // 设置对应索引的工时 empProject.setEmployeeBookedMonths(bookedMonths.get(i)); // 验证打印(此时输出应为正确值) System.out.println("项目:" + project.getName() + " | 工时:" + bookedMonths.get(i)); // 持久化当前实例 empProjectRepo.save(empProject); } return "redirect:/success"; }
三、实体类配置注意事项
确保EmployeeProject为独立实体,关联关系配置正确:
@Entity @Table(name = "employee_project") public class EmployeeProject { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "employee_id", nullable = false) private Employee employee; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "project_id", nullable = false) private Project project; @Column(name = "booked_months") private Double employeeBookedMonths; // 无参/全参构造函数、getter/setter }
- 避免在关联关系中配置错误的级联操作(如
cascade = CascadeType.ALL),防止意外重复保存 - 确保每个
EmployeeProject实例都是独立对象,不要在循环外提前创建
四、调试验证
如果仍有问题,可在保存前打印实例哈希值,确认每次循环都是新对象:
System.out.println("实例哈希:" + empProject.hashCode() + " | 工时:" + empProject.getEmployeeBookedMonths());
若哈希值重复,说明仍在复用同一个EmployeeProject对象,需修正循环内实例化逻辑。
内容的提问来源于stack exchange,提问作者Kayd Anderson
相关产品推荐
相关产品推荐

