How to delete an ManyToMany related object when one part is empty?

房东的猫 提交于 2020-02-04 07:35:32

问题


Here is the BlogPost model :

@Entity
@Table(name = "blog_posts")
public class BlogPost extends Model {
    @Required
    @MaxSize(50)
    @MinSize(3)
    @Column(length=50)
    public String title;

    @Lob
    @Required
    @MaxSize(10000)
    public String description;

    @Temporal(TemporalType.TIMESTAMP)
    public Date created;

    @ManyToMany(targetEntity=PostTag.class, cascade=CascadeType.DETACH)
    @OrderBy("name ASC")
    public List<PostTag> tags;

        // + other fields
}

And the PostTag :

@Entity
@Table(name = "post_tags")
public class PostTag extends Model {
    @Match("^([a-zA-Z0-9\\-]{3,25})$")
    @MinSize(3)
    @MaxSize(25)
    @Required
    @Column(length=25, unique=true)
    public String name;

    @ManyToMany(targetEntity=BlogPost.class, mappedBy="tags", cascade=CascadeType.REMOVE)
    public List<BlogPost> posts;
}

The relation works fine, but what I'd like, is when I remove a tag from my post, if no other post use this tag, then I can remove it definitely from my database.

Here's the code I tried, but generate an Hibernate exception :

public boolean removeTag(PostTag tag) {
    if (!tags.contains(tag)) {
        return false;
    }

    tags.remove(tag);
    save();

    if (tag.posts == null || tag.posts.isEmpty()) {
        tag.delete();
    }

    return true;
}

The exact exception is:

org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update   

java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint fails

I tried to change CascadeType to DELETE_ORPHANS, but it's deprecated, and the new version only seems to works for OneToOne and OneToMany relationships only :/

How can I do ?

Thanks for your help!


回答1:


Ok I've found where the problem was, so I'll explain it here in case someone have the same issue.

The exception was because I was trying to delete a Tag that still had relationship (it was not left alone).

Here is a working solution on how to delete Tags when there is no Posts using it anymore:

public boolean removeTag(PostTag tag) {
    if (!tags.contains(tag)) {
        return false;
    }

    tags.remove(tag);
    save();

    if (PostTag.find("name = ? AND size(posts) = 0", tag.name).first() != null) {
        tag.delete();
    }

    return true;
}



回答2:


Since you are using a bidirectional relation you should update the "backlink"

public boolean removeTag(PostTag tag) {
    if (!tags.contains(tag)) {
        return false;
    }

    tags.remove(tag);       //      remove post -> tag link

    tag.posts.remove(this); // added: remove tag -> post link

    save();

    if (tag.posts == null || tag.posts.isEmpty()) {
        tag.delete();
    }

    return true;
}


来源:https://stackoverflow.com/questions/6215094/how-to-delete-an-manytomany-related-object-when-one-part-is-empty

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!