Search code examples
hibernatemany-to-manycascadecascading-deletes

Hibernate strange behavior. Many to Many. Cascade ALL on Delete


I have following model:

Gallery-Photo-Keyword
|
Keyword

@Entity
@Table(name = "galleries")
public class Gallery extends BaseModel{       

  @OneToMany(cascade = PERSIST, mappedBy = "mainGallery", orphanRemoval = true)
  public List<Photo> photos;

  @ManyToMany(fetch = LAZY, cascade = ALL)
  @JoinTable(name="gallery_keywords", joinColumns=    {@JoinColumn(name="gallery_id")}, inverseJoinColumns={@JoinColumn(name="keyword_id")})
  public List<Keyword> keywords = new ArrayList<>();


@Entity
@Table(name = "photos")
public class Photo extends BaseModel{

  @ManyToOne(fetch = LAZY, cascade = PERSIST) public Gallery mainGallery;

  @ManyToMany(fetch = LAZY, cascade = ALL)
  @JoinTable(name="photo_keywords", joinColumns= {@JoinColumn(name="photo_id")}, inverseJoinColumns={@JoinColumn(name="keyword_id")})
  public List<Keyword> keywords = new ArrayList<>();

@Entity
@Table(name = "keywords")
public class Keyword extends BaseModel {

  @ManyToMany(fetch = LAZY)
  @JoinTable(name="photo_keywords", joinColumns={@JoinColumn(name="keyword_id")}, inverseJoinColumns={@JoinColumn(name="photo_id")})
  public List<Photo> photos = new ArrayList<>();

  @ManyToMany(fetch = LAZY)
  @JoinTable(name="gallery_keywords", joinColumns={@JoinColumn(name="keyword_id")}, inverseJoinColumns={@JoinColumn(name="gallery_id")})
  public List<Gallery> galleries = new ArrayList<>();

PROBLEM: I have a problem on deletion of a photo.
If any keyword which belongs to this photo does not appear in any other photos of this gallery it gets deleted from DB despite on that it has records in photo_keywords table and belongs to other photos in other galleries.

But if keyword belongs to other photos of this gallery it doesn't get deleted.

Deletion code:

public void delete(Photo photo) {
  photo.mainGallery.photos.remove(photo);
  photo.delete();
}

Removing cascade = ALL from Photo class from keywords field annotation solves it. But still why?


Solution

  • Thnx to @JB Nizet.

    Problem was in that both sides had owning and inverse annotations. That's why cascade was ignored. But in documentation it is said that a bidirectional association has an owning side and an inverse (mappedBy) side. That's why behavior was unpredictable. After removing from Keywords unnecessary annotation:

    @JoinTable(name="photo_keywords", joinColumns={@JoinColumn(name="keyword_id")}, inverseJoinColumns={@JoinColumn(name="photo_id")})
    

    And added: mappedBy = "keywords" I started getting reasonable exception: org.hibernate.exception.ConstraintViolationException: could not execute statement So i replaced cascade = ALL with cascade = {PERSIST, MERGE}

    And it was it.