ConcurrentModificationException при удалении ассоциации @ManyToMany Spring Data Jpa - PullRequest
0 голосов
/ 02 ноября 2019

Я схожу с ума от этого ... Я следил за всеми статьями от Мысли о Java и Владом Михалчеа об отображении ассоциаций в hibernate, но я не знаю, почему удаление в @ManyToMany, так или иначе, всегда запутано в моем проектеоб услугах отдыха с Spring Data Jpa.

У меня есть базовая книга -> авторы многих отношений, которые, как мне кажется, я правильно отобразил (по крайней мере, в соответствии с тем, как они рекомендуют в двух ссылках, приведенных выше).

Я перезаписываю equals и hashcode, я написал и использую методы для управления связями между сущностями, но когда я пытаюсь удалить книги из авторов (которые я хочу удалить), я получил ConcurrentModificationException: null, даже если яиспользуйте итератор.

Мои объекты:

@Entity
@Getter
@Setter
@NoArgsConstructor
public class Author {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotNull
    @Size( min = 2, max = 30)
    @Column (length = 30)
    private String firstName;

    @Size( min = 2, max = 30)
    @Column (length = 30)
    private String lastName;

    @ManyToMany(mappedBy = "authors")
    private Set<Book> books = new HashSet<>();

    public Author(@NotNull @Size(min = 2, max = 30) String firstName, @NotNull @Size(min = 2, max = 30) String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public void addBook(Book book){
        this.books.add(book);
        book.getAuthors().add(this);
    }

    public void removeBook(Book book){
        this.books.remove(book);
        book.getAuthors().remove(this);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null) return false;
        if (this.getClass() != o.getClass()) return false;
        return id != null && id.equals(((Author)o).getId());
    }
    @Override
    public int hashCode() {
        return 17;
    }
}

@Entity
@Getter
@Setter
@NoArgsConstructor
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String isbn;
    @NotNull
    private String title;

    //Owning side
    @NotNull
    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinTable(name = "book_author",
               joinColumns = @JoinColumn(name = "book_id"),
               inverseJoinColumns = @JoinColumn(name = "author_id"))
    private Set<Author> authors = new HashSet<>();

    public Book(String title) {
        this.title = title;
        this.isbn = RandomStringUtils.randomAlphanumeric(10);
    }

    public void addAuthor(Author author){
        this.authors.add(author);
        author.getBooks().add(this);
    }

    public void removeAuthor(Author author){
        this.authors.remove(author);
        author.getBooks().remove(this);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null) return false;
        if (this.getClass() != o.getClass()) return false;
        return id != null && id.equals(((Book)o).getId());
    }
    @Override
    public int hashCode() {
        return 13;
    }
}

Мой метод удаления, который находится на моем бизнес-уровне:


    public void deleteAuthor(Long id) {
        Optional<Author> author = authorRepository.findById(id);
        if (author.isPresent()){
            Author au = author.get();
            for (Book book : au.getBooks()) {
                au.removeBook(book);
            }
            authorRepository.delete(au);
        }
    }

У меня есть исключение после первого цикла вдля каждого. Это написано точно так же, как в примерах, поэтому я понятия не имею. Интересно, что делает Spring Data Layer более сложным? Спасибо за вашу помощь!

РЕДАКТИРОВАТЬ: Исключение появляется только в том случае, если мой автор владеет более чем одной книгой

1 Ответ

0 голосов
/ 02 ноября 2019

Видимо, мне удалось решить эту проблему, добавив новый хэш-набор во время итерации.

    public void deleteAuthor(Long id) {
        Optional<Author> author = authorRepository.findById(id);
        if (author.isPresent()) {
            for (Book book : new HashSet<Book>(author.get().getBooks())) {
                author.get().removeBook(book);
            }
            authorRepository.delete(author.get());
        }
    }

, но странно, что я должен это делать, во всех примерах, которые я видел, ничего подобного нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...