我有2个实体,医院和部门,部门通过hospital_id参考其医院。
@Entity
public class Hospital {
...
private Set<Department> departments;
@OneToMany(mappedBy = "hospital", cascade = CascadeType.ALL)
public Set<Department> getDepartments() {
return departments;
}
}
@Entity
public class Department {
...
private Hospital hospital;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "hospital_id")
public Hospital getHospital() {
return hospital;
}
}
我使用Rest API创建实体实例:
@RequestMapping("/create")
@ResponseBody Hospital create(@RequestBody Hospital hospital){
hospital = hospitalService.save(hospital);
return hospital;
}
我发布json有效负载来创建医院:
{"name":"t-hospital", "departments":[{"name": "department1"}]}
由于我使用SpringBoot,Jackson会自动将json有效负载解析为Java Object,其中包括医院和部门。
在我拯救医院之后,我找到了外键:部门中的'hospital_id'未设置。
为什么这样,如果可能的话,如何在保存医院对象时设置外键?
答案 0 :(得分:4)
在持久化实体之前,您应始终在所有者方创建关联,因为所有者方负责创建关系。
修改您的代码如下(包含Java 8代码):
@RequestMapping("/create")
@ResponseBody Hospital create(@RequestBody Hospital hospital){
hospital.getDepartments().forEach(department->department.setHospital(hospital));
hospital = hospitalService.save(hospital);
return hospital;
}
将实体转换为json时可能会遇到新问题,因为Jackson会递归地序列化相关实体,并且您将获得StackOverflow错误。要解决此问题,请添加@JsonManagedReference
以及@OneToMany
注释和@JsonBackReference
以及@ManyToOne
注释。
注意: @JsonManagedReference
和@JsonBackReference
可用于新版本的杰克逊
答案 1 :(得分:0)
从@ManyToOne
注释中删除级联,并将nullable = false
添加到JoinColumn
@ManyToOne
@JoinColumn(name = "hospital_id", nullable = false)
答案 2 :(得分:0)
您可以将获取类型用作惰性。在连接列中,使其不为空。
@Entity
public class Hospital {
...
private Set<Department> departments;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "hospital")
public Set<Department> getDepartments() {
return departments;
}
}
@Entity
public class Department {
...
private Hospital hospital;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "hospital_id", nullable = false)
public Hospital getHospital() {
return hospital;
}
}