如何在一个部分为空时删除ManyToMany相关对象?

时间:2011-06-02 13:22:14

标签: hibernate jpa playframework

以下是BlogPost模型:

@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
}

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;
}

这种关系很好,但我想要的是,当我从帖子中删除标签时,如果没有其他帖子使用此标签,那么我可以从我的数据库中删除它。

这是我尝试的代码,但生成了一个Hibernate异常:

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;
}

确切的例外是:

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

我尝试将CascadeType更改为DELETE_ORPHANS,但它已被弃用,新版本似乎仅适用于OneToOne和OneToMany关系:/

我该怎么办?

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

好的我已经找到了问题的所在,所以我会在这里解释一下,以防有人遇到同样的问题。

例外是因为我试图删除仍然存在关系的标签(它不是单独留下的)。

以下是有关如何在没有帖子使用时删除标签的工作解决方案:

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;
}

答案 1 :(得分:0)

由于您使用的是双向关系,因此您应该更新“反向链接”

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;
}