Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate Bidirectional ManyToMany delete issue

In my project I have entities for users and companies:

@Entity
@Table(name = "users")
public class UserDetails {

    @Id
    @GeneratedValue
    @Column(name = "user_id")
    private int id;

    @Column(name = "first_name")
    @NotEmpty
    @Size(min = 2, max = 20)
    private String firstName;

    @ManyToMany(cascade = CascadeType.REFRESH)
    @JoinTable(name = "users_companies",
            joinColumns = @JoinColumn(name = "user_id"),
            inverseJoinColumns = @JoinColumn(name = "company_id"))
    private Set<CompanyDetails> userCompanies = new HashSet();

    //getters and setters of course...
}

@Entity
@Table(name = "companies")
public class CompanyDetails {
    @Id
    @GeneratedValue
    @Column(name = "company_id")
    private int id;

    @Column(name = "name")
    @NotEmpty
    @Size(min = 1, max = 255)
    private String name;

    @ManyToMany(mappedBy = "userCompanies")
    private Set<UserDetails> companyUsers = new HashSet();

}

I assign user to company in view and then try to delete. When I delete a user everything is ok - user deleted, record from 'users_companies' table deleted too and company remains (as necessary). But when I try to delete a company I have stack trace with following root cause:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`d_torianik/users_companies`, CONSTRAINT `FK447D806437A764EB` FOREIGN KEY (`company_id`) REFERENCES `companies` (`company_id`))

Could you help me resolve this issue? Thank you.

like image 735
sidlejinks Avatar asked Mar 01 '13 10:03

sidlejinks


2 Answers

I know this is old but it may help someone... I was trying to do the exact same thing - deleting from each main table to delete the referenced records first in the joined table and then delete the record from the main table. benzonico's post is valid but there is a more simple way to do this (without having to remove the records from the joined table yourself). The mapping at companies table needs to be changed to be a main table as well (don't use mappedBy):

@Entity
@Table(name = "companies")
public class CompanyDetails {
    @Id
    @GeneratedValue
    @Column(name = "company_id")
    private int id;

    @Column(name = "name")
    @NotEmpty
    @Size(min = 1, max = 255)
    private String name;

    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinTable(name = "users_companies",
    joinColumns = {@JoinColumn(name = "company_id")},
    inverseJoinColumns = @JoinColumn(name = "user_id"))
    private Set<UserDetails> companyUsers = new HashSet();

}

That should do the trick. Now whenever you delete a company, Hibernate will first delete the records in users_companies and then it will delete the company itself. More info here: http://www.codereye.com/2009/06/hibernate-bi-directional-many-to-many.html

like image 172
Koshera Avatar answered Dec 01 '22 00:12

Koshera


You have to have a CascadeType.REMOVE in your Cascade annotation of the property companyUsers of the entity CompanyDetails.

[Edit after comments]

Sorry i missed one thing in my answer is that it is a many to many. So the cascade delete won't work. Then the problem is that the responsible for the relationship is the UserDetails class. That is why it works on one way and not in the other one. Before deleting the company you may have to remove this company from the userCompanies set in each UserDetails of the companyUsers set.

like image 38
benzonico Avatar answered Dec 01 '22 00:12

benzonico