Spring JPA如何创建带关联关系的实体及关联已存在实体
问题排查与解决方案
你给出的无法运行的代码存在第一处显性错误:实例化地址对象时类名拼写错误,实体类定义名为Adresse,代码中写为Adress(缺失末尾的字母e),修正拼写后可按以下两种场景正确实现关联。
1. 新建Person同时级联新建关联Adresse
你在Person实体的adresse字段上配置了@OneToOne(cascade = CascadeType.ALL),本身已经支持保存Person时自动持久化传入的新创建、未入库的Adresse对象,不需要提前单独保存地址。
正确代码示例:
personRepository.save(new Person( new Name("Test","Test"), new Adresse("Street","Number","PLZ","Town"), // 注意类名拼写正确 LocalDate.parse("2000-01-01"), "email@email.com", "911" ));
如果修正拼写后仍报错,检查Person类的无参构造权限:当前无参构造为
private,JPA实现要求实体无参构造至少为protected级别,将private Person() {}修改为protected Person() {},和Adresse类的无参构造权限保持一致即可。
2. 关联已提前持久化的Adresse对象
如果Adresse已经提前存入数据库,不能直接new一个同参数的Adresse实例传入,必须先通过Adresse的主键ID从Repository查询出数据库托管状态的Adresse实例,再关联到Person。
正确代码示例:
// 提前保存地址,拿到入库后生成的地址ID Adresse persistedAdresse = adresseRepository.save(new Adresse("Street","Number","PLZ","Town")); Long adresseId = persistedAdresse.getAdresseID(); // 根据ID查询数据库中已存在的地址实例,查询失败可以抛出业务异常 Adresse dbAdresse = adresseRepository.findById(adresseId) .orElseThrow(() -> new RuntimeException("指定ID的地址不存在")); // 关联查询到的地址实例,保存Person即可 personRepository.save(new Person( new Name("Test","Test"), dbAdresse, LocalDate.parse("2000-01-01"), "email@email.com", "911" ));
配置优化提示
如果业务场景中Adresse是可被多个实体复用的公共数据,不建议配置CascadeType.ALL全量级联,否则删除/更新Person时会连带操作已存在的地址数据,建议按需配置级联规则,比如仅保留CascadeType.PERSIST满足新建Person时同步新建地址的需求即可。
内容的提问来源于stack exchange,提问作者salteax1
相关产品推荐
相关产品推荐

