简体   繁体   中英

How to delete many-to-many relationship?

I have a many-to-many relationship (Car & driver) How, when deleting a Driver, delete a link in the driver_car table and delete cars that were bound to this driver, and vice versa, when deleting a car, simply delete a car and links in the driver_car table that are not associated with this by car?

My BaseEntity:

 @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;
        }
    }

My 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;
    }
}

My Car:

@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;
}
}

Delete Car:

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

Delete Driver:

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

One should be very cautious about using CascadeType.ALL for @ManyToMany associations, since this might yield surprising results as described eg here:
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.

So a better way would be eg to have a dedicated service logic which specifies exactly which entities are to be deleted and which of course also takes care of synchronizing both sides of the association.
This way there can also be a simple check whether a previously associated Car has no more associated Driver s after one was deleted, so that the "orphan" Car can then be deleted as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM