java - Springboot 2.1.9.RELEASE - 使用 JPA 持久化具有父子关系的实体
问题描述
我在mysql中的表Employee
和表之间有一对多的关系。Address
我希望当我使用子数据持久保存父级时,首先创建父级并parent_id
自动在子表中使用它。我收到以下错误。
任何帮助将不胜感激:
父代码:
@Entity
@Table(name = "employee")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(length = 6)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Temporal(TemporalType.DATE)
private Date dob;
@Column(name="email_address")
private String emailAddress;
@Column(name="first_name")
private String firstName;
@Column(name="gender")
private String gender;
@Column(name="last_name")
private String lastName;
@Column(name="user_id")
private String userName;
@Column(name="password")
private String password;
@Column(name="email_verified")
private String emailVerification;
@OneToMany(targetEntity = Address.class, mappedBy = "employee", orphanRemoval = true,
cascade =
CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Address> addresses = null;
public Employee() {
}
public Employee(long id) {
this.id = id;
}
孩子:
@Entity
@Table(name = "address")
public class Address implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(length = 6)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Basic
private String address1;
@Basic
private String address2;
@Basic
private String city;
@Basic
private String zip;
@Basic
@Column(name = "emp_id")
private String empId;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "emp_id", nullable = false, updatable=false, insertable=false)
@JsonIgnore
private Employee employee;
@Basic
private int state_id;
public Address() {
}
public Address(long id) {
this.id = id;
}
public long getId() {
return this.id;
}
控制器:
@CrossOrigin (origins = "*" )
@PostMapping("/employee")
public Employee createEmployee(@Valid @RequestBody Employee employee) {
return employeeRepository.save(employee);
}
JSON输入:
{
"dob": "2001-11-12",
"emailAddress": "aaa@gmail.com",
"firstName": "John",
"gender": "M",
"lastName": "Wilson",
"userName": "jon",
"password": "pass",
"emailVerification": null,
"addresses": [
{
"address1": "123 My Street",
"address2": null,
"city": "MyCity1",
"zip": "11111",
"stateId": 1
},
{
"address1": "567 My Street",
"address2": null,
"city": "MyCity2",
"zip": "22222",
"stateId": 1
}
]
}
错误
Hibernate:
insert
into
address
(address1, address2, city, emp_id, state_id, zip)
values
(?, ?, ?, ?, ?, ?)
2021-04-28 22:17:19.067 RACE 25508 --- [nio-9090-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [567 My Street]
2021-04-28 22:17:19.067 TRACE 25508 --- [nio-9090-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [VARCHAR] - [null]
2021-04-28 22:17:19.067 TRACE 25508 --- [nio-9090-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [3] as [VARCHAR] - [MyCity2]
2021-04-28 22:17:19.067 TRACE 25508 --- [nio-9090-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [4] as [VARCHAR] - [null]
2021-04-28 22:17:19.067 TRACE 25508 --- [nio-9090-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [5] as [INTEGER] - [1]
2021-04-28 22:17:19.067 TRACE 25508 --- [nio-9090-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [6] as [VARCHAR] - [22222]
2021-04-28 22:17:19.071 WARN 25508 --- [nio-9090-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1048, SQLState: 23000
2021-04-28 22:17:19.071 ERROR 25508 --- [nio-9090-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper : Column 'emp_id' cannot be null
2021-04-28 22:17:19.094 WARN 25508 --- [nio-9090-exec-2] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null];
解决方案
一种选择是遍历所有地址并employee
手动设置属性。您应该手动执行此操作,因为 JSON 反序列化不会触及该字段,即使没有@JsonIgnore
注释也是如此。但这只是问题的表面。
您正在设置updatable=false, insertable=false
该employee
属性。还有另一个属性String empId
映射到同一列,表示您要手动管理关系。列/属性的类型应该与相关实体的 PK/id 相同,所以long
!而且,鉴于 JSON 不包含empId
两者,您仍然需要手动设置它;但你在创作的时候并不知道!如果您删除该属性Address.empId
并手动设置它,它应该可以工作updatable=false, insertable=false
。employee
如果您希望 Jackson 为您执行此操作,除了上一段中讨论的任务(删除和属性)和删除当然之外,您可以@JsonManagedReference
在Employee.addresses
属性和@JsonBackReference
上使用。在此处查看详细说明:Address.employee
updatable=false, insertable=false
String empId
@JsonIgnore
@JsonManagedReference
@OneToMany(targetEntity = Address.class, mappedBy = "employee", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Address> addresses = null;
@JsonBackReference
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "emp_id", nullable = false)
private Employee employee;
免责声明:我反对混合 JPA 和 Jackson 注释。这确实很方便,因为您不需要单独的 DTO 类,不需要映射逻辑,也不需要担心进行实体 ↔ DTO 转换所需的 CPU/内存。另一方面,数据传输和数据持久性是两个完全不同的问题,所以 SOLID 付诸东流。并且有可能发送不应该被客户端看到的字段(例如User
实体的密码或电子邮件)。
推荐阅读
- ansible - 如何在 Ansible 中构建条件命令?
- r - R使用面向对象编程(S3和S4)将多个函数转换为一个对象
- java - 在列表的序列化中包含具有数组索引的字段
- xslt - 不允许将多个项目的序列作为 fn:generate-id() 的第一个参数(
, ) - sql - 在视图上的触发器上插入功能
- c# - 用数组更新标签
- django - Django:使用 GET 将额外的变量传递给 LoginView?
- python - 如何循环返回网页抓取结果并保存到 Excel 文件?
- asp.net-core - 使用 AutoMapper 进行多对多关系展平
- c# - C# Telegram.Bot SendTextMessageAsync 不发送任何消息