Как удалить объект, связанный с ManyToMany, когда одна часть пуста? - PullRequest
2 голосов
/ 02 июня 2011

Вот модель 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 ]

2 голосов
/ 02 июня 2011

Хорошо, я нашел, где была проблема, поэтому я объясню ее здесь на случай, если у кого-то возникнет такая же проблема.

Исключением было то, что я пытался удалить тег, который все еще имел отношение (это не было оставлено в покое).

Вот рабочее решение о том, как удалять теги, когда сообщения больше не используют его:

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;
}
0 голосов
/ 04 июня 2011

Поскольку вы используете двунаправленное отношение, вам следует обновить «обратную ссылку»

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...