Java Springboot 2.1.9.RELEASE-使用JPA持久化具有父子关系的实体

Java Springboot 2.1.9.RELEASE-使用JPA持久化具有父子关系的实体,java,mysql,json,jpa,Java,Mysql,Json,Jpa,我在mysql中的Employee和Address表之间有一对多关系。我希望在使用子数据持久化父对象时,首先创建父对象,并在子表中自动使用其parent\u id。我得到以下错误 任何帮助都将不胜感激: 父代码: @Entity @Table(name = "employee") public class Employee implements Serializable { private static final long serialVersionUID = 1L

我在mysql中的
Employee
Address
表之间有一对多关系。我希望在使用子数据持久化父对象时,首先创建父对象,并在子表中自动使用其
parent\u 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;
    }
控制器:

@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
    }
  ]
}
错误


一个选项是遍历所有地址并手动设置
employee
属性。您应该手动执行,因为JSON反序列化将不会触及该字段,即使没有
@JsonIgnore
注释。但这只是问题的表面

您正在
employee
属性上设置
updateable=false,insertable=false
。另一个属性是
字符串empId
,它映射到同一列,表示您希望手动管理关系。列/属性的类型应与相关实体的PK/id相同,因此
long
!而且,考虑到JSON也不包含
empId
,您仍然需要手动设置它;但是你在创造的时候还不知道!如果删除
Address.empId
属性和
updateable=false,insertable=false
并手动设置
employee
,它应该可以工作

如果您希望Jackson为您这样做,除了上一段中讨论的任务外,还可以在
Employee.addresses
属性上使用
@JsonManagedReference
,在
Address.Employee
属性上使用
@JsonBackReference
(删除
updateable=false,insertable=false
字符串empId
属性)并当然删除
@JsonIgnore
。请参阅详细说明:

@JsonManagedReference
@OneToMany(targetEntity=Address.class,mappedBy=“employee”,orphanRemoving=true,cascade=CascadeType.ALL,fetch=FetchType.EAGER)
专用地址集=空;
@JsonBackReference
@manytone(fetch=FetchType.LAZY,可选=false)
@JoinColumn(name=“emp_id”,nullable=false)
私人雇员;

免责声明:我反对混合使用JPA和Jackson注释。这确实很方便,因为您不需要单独的DTO类,不需要映射逻辑,也不需要担心执行转换实体所需的CPU/内存↔ DTO。另一方面,数据传输和数据持久性是两个完全不同的关注点,因此SOLID将付诸东流。并且有可能发送客户端不应该看到的字段(例如用户的密码或电子邮件)。

有效。非常感谢!!!
{
  "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];