一对多映射外键未更新:员工技能多选表单关联问题
问题描述
我开发了一款员工表单,员工可通过下拉框选择多项技能,点击提交按钮后表单需完成保存,同时在formskills关联表中记录formid与skillid的映射关系,但目前无法实现该映射,尝试多种在线方案均无效。
- 技能下拉框:前端展示的多选技能下拉组件,支持用户勾选多个技能选项
- 前端请求载荷:提交表单时发送的请求体数据,包含表单基本信息及选中的技能列表
数据库表结构
- FormTable(表单表):存储员工表单基本信息,包含
formid(主键)、姓名、邮箱、手机号等字段 - SkillTable(技能表):存储所有可选技能,包含
skill_id(主键)、skill_name(技能名称)字段 - FormSkills Table(表单技能关联表):关联表单与技能的中间表,包含
formid(外键关联FormTable)、skillid(外键关联SkillTable)两个字段,用于记录表单对应的技能映射关系
后端实体代码
FormModel(表单实体)
@Entity @Table(name="forms") @SequenceGenerator(name="seq", initialValue=25, allocationSize=100) public class FormModel implements Serializable { @Id @GeneratedValue(strategy = GenerationType.TABLE,generator = "seq") private Long formid; private String firstName; private String lastName; @Column(nullable=false) private String Email; private long mobileNumber; private int overalExperience; private int relaventExperience; private Date dateOfBirth; private String adarNumber; @Column(name="name_of_college") private String nameOfCollege; private String certificates; @OneToMany(mappedBy="formmodel",cascade=CascadeType.ALL,orphanRemoval=true) private List<SkillsModel> skills; }
SkillsModel(技能实体)
@Entity @Table(name="skills") public class SkillsModel implements Serializable{ @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) @Column(name="skill_id") private Integer skillid; @Column(name="skill_name") private String skillname; public SkillsModel() {} public SkillsModel(Integer skillid, String skillname) { super(); this.skillid = skillid; this.skillname = skillname; } @ManyToOne(fetch = FetchType.LAZY) @JoinTable(name="formskills",joinColumns = {@JoinColumn(name="skillid")},inverseJoinColumns = {@JoinColumn(name="formid")}) private FormModel formmodel; public SkillsModel(Integer skillid, String skillname, FormModel formmodel) { super(); this.skillid = skillid; this.skillname = skillname; this.formmodel = formmodel; } }
Controller(控制器)
@CrossOrigin(origins = "http://localhost:4200") @RestController public class FormController { @Autowired private FormService service; @GetMapping("/getskills") public List<SkillsModel> getskills() { return service.getskills(); } @PostMapping(value="/saveuser") public ResponseEntity<Object> createUser(@RequestBody FormModel model) { System.out.println(model.getSkills().get(0)); FormModel modelform=service.createuserform(model); URI location=ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}") .buildAndExpand(modelform.getFormid()).toUri(); return ResponseEntity.created(location).build() ; } @GetMapping("/getforms") public List<FormModel> getformdata() { return service.getformdata(); } }
Service(服务层)
@Service public class FormService { @Autowired private FormRepository formrepo; @Autowired private Skillsrepository skillsrepo; public FormModel createuserform(FormModel userform) { FormModel modelform=formrepo.save(userform); return modelform; } public List<SkillsModel> getskills() { List<SkillsModel> getskills=new ArrayList<>(); getskills=skillsrepo.findAll(); for(SkillsModel model :getskills) { System.out.println(model.getSkillid() + model.getSkillname()); } return getskills; } public List<FormModel> getformdata() { List<FormModel> formlist= formrepo.findAll(); System.out.println(formlist); return formlist; } }
问题分析与解决方案
核心问题
- 关联映射配置错误:
SkillsModel中的@JoinTable字段映射与数据库实际字段不匹配,且当前用一对多+多对一的方式实现多对多关系,不符合业务逻辑(一个技能可被多个表单关联) - 关联关系未维护:保存表单时,未为选中的技能设置对应的表单引用,JPA无法识别关联关系
- 前端数据处理缺失:若前端仅传入技能ID,后端直接接收为
SkillsModel实例会被JPA判定为新技能,而非关联已有技能
修复步骤
1. 修正实体关联映射(推荐多对多配置)
表单与技能是多对多关系,直接用@ManyToMany更贴合业务:
- 修改
FormModel的技能关联:
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinTable( name = "formskills", joinColumns = {@JoinColumn(name = "formid")}, inverseJoinColumns = {@JoinColumn(name = "skillid", referencedColumnName = "skill_id")} ) private List<SkillsModel> skills;
- 移除
SkillsModel中的formmodel字段及对应的@ManyToOne、@JoinTable配置,多对多关系只需在一方维护即可
2. 维护关联关系(保留一对多/多对一时)
在FormService的createuserform方法中,为每个技能绑定表单实例:
public FormModel createuserform(FormModel userform) { if(userform.getSkills() != null) { for(SkillsModel skill : userform.getSkills()) { skill.setFormmodel(userform); } } return formrepo.save(userform); }
3. 处理前端传入的技能ID
如果前端仅传技能ID列表,先从数据库查询真实技能实例再关联:
public FormModel createuserform(FormModel userform) { List<SkillsModel> existingSkills = new ArrayList<>(); if(userform.getSkills() != null) { for(SkillsModel skill : userform.getSkills()) { skillsrepo.findById(skill.getSkillid()).ifPresent(existingSkills::add); } userform.setSkills(existingSkills); // 若用一对多需绑定表单,多对多则无需此步骤 existingSkills.forEach(skill -> skill.setFormmodel(userform)); } return formrepo.save(userform); }
内容的提问来源于stack exchange,提问作者Sirisha K
相关产品推荐
相关产品推荐

