JPA Spring Boot Hibernate Rest API:为啥Hibernate在插入之前会删除?

Posted

技术标签:

【中文标题】JPA Spring Boot Hibernate Rest API:为啥Hibernate在插入之前会删除?【英文标题】:JPA Spring Boot Hibernate Rest API: Why does Hibernate delete before when insert into?JPA Spring Boot Hibernate Rest API:为什么Hibernate在插入之前会删除? 【发布时间】:2021-04-02 04:11:06 【问题描述】:

我想描述以下场景: 我使用 Spring Boot 作为后端,使用 mysql 数据库和 Angular 9 作为前端。

员工和预订之间是多对多关系。

MySQL

员工:

emp_id name
1 test

预订:

book_id attribute
1 test

book_emp:

emp_id book_id
1 1

到目前为止一切正常,但是当我将更多值发布到链接表时,所有其他元组都被删除。

book_emp:

emp_id book_id
1 2

结果应该是这样的:

emp_id book_id
1 1
1 2

控制台

Hibernate: insert into booking (hours, total, wadge_eur, year) values (?, ?, ?, ?)
Hibernate: delete from book_emp where emp_id=?
Hibernate: insert into book_emp (emp_id, book_id) values (?, ?)

为什么 Hibernate 从 book_emp 中删除?我已经尝试了 ManyToMany 注释类中所有可能的变体。不幸的是没有成功。我认为问题出在 RestController。

我之前试过 PUT,但结果和 POST 一样。

春季启动 Employee.java

@ManyToMany(cascade =  CascadeType.ALL , fetch = FetchType.LAZY)
    @JoinTable(name = Constant.BOOK_EMP, joinColumns = @JoinColumn(name = Constant.EMP_ID, referencedColumnName = Constant.EMP_ID), 
            inverseJoinColumns = @JoinColumn(name = Constant.BOOK_ID, referencedColumnName = Constant.BOOK_ID), 
            uniqueConstraints = 
            @UniqueConstraint(columnNames =  Constant.EMP_ID, Constant.BOOK_ID ) 
            )
    @JsonBackReference(value = Constant.BOOKING)
    private Set<Booking> bookings;

Booking.java

@ManyToMany(mappedBy = "bookings")
       private Set<Employee> employees;

EmployeeController.java:

@PostMapping(Constant.EMPLOYEE + "/id")
    public Employee postEmployeeById(@PathVariable(value = "id") Long employeeId,
            @Valid @RequestBody Employee employeeDetails) throws ResourceNotFoundException 
        Employee employee = employeeRepository.findById(employeeId)
                .orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id ::" + employeeId));
                
        employee.setBookings(employeeDetails.getBookings());
                
        return employeeRepository.save(employee);

EmployeeRepository.java

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> 

角度 员工服务.ts

  updateEmployeeData(id: number, value: any): Observable<Object> 
    return this.httpClient.post(`$this.baseURL + this.empURL/$id`, value);
  

如何让 Hibernate 停止删除?

【问题讨论】:

但这就是你要求它做的事情:employee.setBookings(employeeDetails.getBookings());。在应用新关联之前,它首先必须删除旧关联。 我应该问什么? 好吧,您的预订集合似乎已在客户端更新。因此,在这种情况下,id 为 1 的预订将被删除,因此您只剩下预订 2。 【参考方案1】:

[分辨率]

员工类

//LOMBOK 
...
@EqualsAndHashCode(exclude = "bookings")
...

    @ManyToMany(cascade =  CascadeType.ALL , fetch = FetchType.LAZY)
        @JoinTable(name = Constant.BOOK_EMP, joinColumns = @JoinColumn(name = 
         Constant.EMP_ID, referencedColumnName = Constant.EMP_ID, updatable = false, 
         insertable = false), 
            inverseJoinColumns = @JoinColumn(name = Constant.BOOK_ID, referencedColumnName = Constant.BOOK_ID, updatable = false, insertable = false), 
            uniqueConstraints = 
            @UniqueConstraint(columnNames =  Constant.EMP_ID, Constant.BOOK_ID ) 
            )
    @JsonBackReference(value = Constant.BOOKING)
    private Set<Booking> bookings;
    
    @JsonIgnore
    public boolean addEmpBook(Set<Booking> set) 
            return this.bookings.addAll(set);           
    

预订舱位

//LOMBOK: 
...
@EqualsAndHashCode(exclude = "employees")
...
    
    @JsonIgnore
    @ManyToMany(mappedBy = "bookings")
    private Set<Employee> employees;

员工控制器

    @PostMapping(Constant.EMPLOYEE + "/id")
    public Employee postEmployeeById(@PathVariable(value = "id") Long employeeId,
            @Valid @RequestBody Employee employeeDetails) throws ResourceNotFoundException 
        Employee employee = employeeRepository.findById(employeeId)
                .orElseThrow(() -> new ResourceNotFoundException("Employee not found for 
                this id ::" + employeeId));
        
        employee.addEmpBook(employeeDetails.getBookings());
        return employeeRepository.save(employee);
    
    

控制台休眠

Hibernate: insert into booking (hours, total, wadge_eur, year) values (?, ?, ?, ?)
Hibernate: insert into book_emp (emp_id, book_id) values (?, ?)

【讨论】:

以上是关于JPA Spring Boot Hibernate Rest API:为啥Hibernate在插入之前会删除?的主要内容,如果未能解决你的问题,请参考以下文章

制作多个 EntityManager(Spring-Boot-JPA、Hibernate、MSSQL)

Spring Boot / JPA / Hibernate,如何根据 Spring 配置文件切换数据库供应商?

Spring boot之 JPA/Hibernate/Spring Data

Spring Boot JPA Hibernate - 以毫秒精度存储日期

当加载 spring-boot 和 spring-data-jpa 时,Hibernate 无法加载 JPA 2.1 Converter

Spring Boot 2.1 缺少多个 org.hibernate.jpa.event 类