如何删除many-to-many关系?

How to delete many-to-many relationship?

我有一个many-to-many关系(车&driver)如何,当删除一个Driver时,在driver_car中删除一个linktable 并删除绑定到此 driver 的汽车,反之亦然,删除汽车时,只需删除汽车和 driver_car table 中的 link 即可与汽车无关吗?

我的基础实体:

 @MappedSuperclass
    public abstract class BaseEntity {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    
        @Temporal(TemporalType.TIMESTAMP)
        private Date created;
    
        @Temporal(TemporalType.TIMESTAMP)
        private Date updated;
    
    
        private Boolean visible;
    
        @Column(name = "image_url")
        private String imageUrl;
    
        public BaseEntity() {
            this.created = new Date();
            this.updated = new Date();
            this.visible = true;
        }
    
        @PreUpdate
        public void preUpdate() {
            this.updated = new Date();
        }
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public Date getCreated() {
            return created;
        }
    
        public void setCreated(Date created) {
            this.created = created;
        }
    
        public Date getUpdated() {
            return updated;
        }
    
        public void setUpdated(Date updated) {
            this.updated = updated;
        }
    
        public Boolean getVisible() {
            return visible;
        }
    
        public void setVisible(Boolean visible) {
            this.visible = visible;
        }
    
        public String getImageUrl() {
            return imageUrl;
        }
    
        public void setImageUrl(String imageUrl) {
            this.imageUrl = imageUrl;
        }
    }

我的Driver:

@Entity
@Table(name = "drivers")
public class Driver extends BaseEntity {

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    private String notes;
    private double balance;

    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(
            name = "driver_car",
            joinColumns = @JoinColumn(name = "driver_id"),
            inverseJoinColumns = @JoinColumn(name = "car_id"))
    private Set<Car> cars;

    public Driver() {
        super();
        this.cars = new HashSet<>();
    }

    public Set<Car> getCars() {
        return cars;
    }

    public void setCars(Set<Car> cars) {
        this.cars = cars;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getNotes() {
        return notes;
    }

    public void setNotes(String notes) {
        this.notes = notes;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }
}

我的车:

@Entity
@Transactional
public class Car extends BaseEntity {

@Column(name = "cars_name")
private String carName;

private String color;

@Column(name = "engine_of_capacity")
private double engineCapacity;

@Column(name = "years_of_issue")
private Integer yearsOfIssue;

@Column(name = "car_number")
private String carNumber;

@ManyToMany(mappedBy = "cars", cascade = CascadeType.ALL)
private Set<Driver> drivers;

public Car() {
    super();
    drivers = new HashSet<>();
}

public Set<Driver> getDrivers() {
    return drivers;
}

public void setDrivers(Set<Driver> drivers) {
    this.drivers = drivers;
}

public String getCarNumber() {
    return carNumber;
}

public void setCarNumber(String carNumber) {
    this.carNumber = carNumber;
}

public String getCarName() {
    return carName;
}

public void setCarName(String carName) {
    this.carName = carName;
}

public String getColor() {
    return color;
}

public void setColor(String color) {
    this.color = color;
}

public double getEngineCapacity() {
    return engineCapacity;
}

public void setEngineCapacity(double engineCapacity) {
    this.engineCapacity = engineCapacity;
}

public Integer getYearsOfIssue() {
    return yearsOfIssue;
}

public void setYearsOfIssue(Integer yearsOfIssue) {
    this.yearsOfIssue = yearsOfIssue;
}
}

删除汽车:

@Override
public void delete(Long id) {
    entityManager.createQuery("delete from Car s where s.id = :id")
            .setParameter("id", id)
            .executeUpdate();
}

删除Driver:

@Override
public void delete(Long id) {
    entityManager.createQuery("delete from Driver d where d.id = :id")
            .setParameter("id", id)
            .executeUpdate();
}

对于 @ManyToMany 关联使用 CascadeType.ALL 应该非常谨慎,因为这可能会产生令人惊讶的结果,例如这里:
https://thorben-janssen.com/best-practices-for-many-to-many-associations-with-hibernate-and-jpa/#The_CascadeType_you_should_avoid_at_all_costs

In the best case, it only creates performance issues, but in the worst case, it might also remove more records than you intended.

所以更好的方法是,例如有一个专门的服务逻辑,它确切地指定要删除哪些实体,当然也需要照顾 synchronizing both sides of the association.
这样也可以简单地检查以前关联的 Car 在删除后是否没有更多的关联 Driver,这样“孤儿” Car 也可以被删除.