javaspring-bootspring-data-jpacascadecascading-deletes

deleteById() method not working with ManyToMany mapping: Spring Boot and JPA


I have a scenario in which I have a ManyToMany mapping between a Policy and a County entity tables. Here is the entity code-
InsurancePolicy.java-

@Entity
@Table(name = "insurance_policy")

public class InsurancePolicy {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="policy_id")
    private long policyId;

    @Column(name="policy_name",nullable = false,unique = true)
    private String policyName;

    //Short description
    @Column(name="policy_description",nullable = false)
    private String policyDescription;

    //Long description
    @Column(name="choose_description",nullable = false)
    private String chooseDescription;


    //many policies can belong to one category
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "company_id", nullable = false)
    private Company company;

    //many policies can belong to one category
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="category_id",nullable=false)
    private Category category;

    @ManyToMany(mappedBy = "queriedPolices",fetch = FetchType.LAZY,cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    private Set<User> usersQueried=new HashSet<>();

    @OneToMany(mappedBy = "policy", cascade = {CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REMOVE},fetch = FetchType.LAZY)
    private Set<PolicyCounty> policyCounties = new HashSet<>();

PolicyCounty.java- (Relationship table)

@Data
@Entity
@Table(name="policy_county")
public class PolicyCounty {


    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="policy_county_id")
    private long policyStateId;

    @ManyToOne
    @JoinColumn(name="policy_id")
    private InsurancePolicy policy;


    @ManyToOne
    @JoinColumn(name = "county_id")
    private County county;

    @Column(name="cost",nullable = false)
    private double cost;
}

County.java-

@Entity
@Data
@Table(name="county")
public class County {

    @Id
    @Column(name="countyid")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long countyId;

    @Column(name="countyname",nullable = false,unique = true)
    private String countyName;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "adminId", nullable = false)
    private Admin admin;

    @OneToMany(mappedBy = "county", cascade = {CascadeType.MERGE,CascadeType.PERSIST},fetch = FetchType.LAZY)
    private Set<PolicyCounty> policyStates = new HashSet<>();

}

Problem-
I want to delete the InsurancePolicy entity and also delete the corressponding entities in the PolicyCounty table. For it, I write the delete method-

@Override
    public long deletePolicy(long policyId) {
        boolean isPresent=insurancePolicyRepository.existsById(policyId);
        if(isPresent){
            insurancePolicyRepository.deleteById(policyId);
            return insurancePolicyRepository.count();
        }
        throw new ResourceNotFoundException("Policy with id "+policyId+" not found");
    }

Now, when I try to delete, the entities do not get deleted from the table. I am not getting any exception during this operation. I doubt that the problem is with the Cascade Types used with entities. Please help me understand this.


Solution

  • in your code you should have an filed in InsurancePolicy that links to County

        @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    @JoinTable(name = "policy_county",
            joinColumns = @JoinColumn(name = "insurance_policy_id"),
            inverseJoinColumns = @JoinColumn(name = "county_id"))
    private Set<County> counties= new HashSet<>();
    

    and you should have filed in county like this

     @ManyToMany(mappedBy = "insurance_policy", fetch = FetchType.LAZY)
    private Set<InsurancePolicy > students = new HashSet<>();
    

    hibernate does not now you have many to many relation if you dont have it.

    but If you have extra fields in your join table, such as a cost field, Hibernate will not automatically delete the corresponding entries from the join table when you delete a entity. Instead, you need to manually delete the entries from the join table using a native SQL query or Hibernate's Criteria API.

    another option is convert many to many relation into 2 one to many relation like this :

    public class Student {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "name")
    private String name;
    
    @OneToMany(mappedBy = "student", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Enrollment> enrollments = new HashSet<>();}
    
    public class Course {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "name")
    private String name;
    
    @OneToMany(mappedBy = "course", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Enrollment> enrollments = new HashSet<>();}
    
    
    public class Enrollment {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToOne(fetch = FetchType.LAZY)
    private Student student;
    
    @ManyToOne(fetch = FetchType.LAZY)
    private Course course;
    
    @Column(name = "cost")
    private BigDecimal cost;}
    

    In the above example, the "Student" entity has a one-to-many relationship with the "Enrollment" entity, and the "Course" entity also has a one-to-many relationship with the "Enrollment" entity. Both relationships have cascading deletes set up using the CascadeType.ALL option, which will cause associated "Enrollment" entities to be deleted automatically when a "Student" or "Course" entity is deleted. The orphanRemoval attribute is set to true, which will remove any "Enrollment" entities that are no longer associated with a "Student" or "Course" entity.

    With cascading deletes set up, you can delete a "Student" or "Course" entity and all associated "Enrollment" entities will be deleted automatically: