Search code examples
javahibernatemany-to-many

Hibernate many to many proper delete


I'm trying to create a really really dummy dictionary backend using hibernate and j2ee. (Just to learn these technologies.)

I have two entities 'Word' and 'Category' and there is a many to many relation between these. What I would like to reach is that, if I delete a category then it is getting removed from all of the affected words' categories but the words still exist and if I delete a word then from the category point of view nothing happens. Even there is no more word in that category the category should be exist.

Currently I cannot delete a category if there is one word in that category at least. (Recive: org.hibernate.exception.ConstraintViolationException: could not execute statement) And when I delete a word if there is no more word in that category then the category is getting removed with the word as well.

Here is how I declared the entities:

@Entity
@Table(name = "Word")
public class Word {
    @Id()
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    private String uid;

    @NotNull
    @Column(nullable = false, length = 512)
    private String hungarian;

    @NotNull
    @Column(nullable = false, length = 512)
    private String english;

    @JoinColumn(name = "categories_uid")
    @ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.ALL })
    @Valid
    private Set<Category> categories;
...
}

@Entity
@Table(name = "Category")
public class Category {
    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    private String uid;

    @NotNull
    @Size(min = 3, max = 512)
    @Column(nullable = false, length = 512)
    private String name;
...
}

I didn't create Set in the Category class because there would be a lot of word in that set which could cause performance problem. If it was possible, I wouldn't create a Set in the Category class.

I thought that CascadeType.ALL should handle this.

Thanks in advance.


Solution

  • Your delete operation fails because of foreign key constraint. In this case you can define an owner side in your many-to-many relationship which is Word and then when you remove a Word the relationship will be handled automatically. But if you want to remove a Category you have to remove it manually like this:

          @Entity
          public class Word {
          @ManyToMany
          Set<Category> categories;
    
          @Entity
          public class Category {
          @ManyToMany(mappedBy="categories")
          Set<Word> words;
    
           // call you entity manager to remove a category
           em.remove(category);
           for (Word word : category.words) {
                word.categories.remove(category);
           }