весна jpa многие ко многим удаляют только ассоциацию - PullRequest
0 голосов
/ 24 мая 2018

Я кое-что выяснил, как удалить только ассоциацию «многие ко многим», не удаляя ни одну из сущностей, и все, что я нашел, это учебные пособия или примеры того, как удалить одну из сущностей без каскадного удаления в другую сущность или в другую.вся таблица (при использовании CascadeType.ALL).

Итак: у меня есть две таблицы и таблица «многие ко многим», содержащая отношения между ними.

authors( int author_id, varchar author_name )
books( int book_id, varchar book_name )
author_x_book( int author_id, int book_id )

У автора может быть много книг,книга может иметь много авторов.Я не вхожу в детали о первичных ключах и внешних ключах и почему я выбрал этот дизайн и т. Д.

JPA Entities:

@Entity
@Table(name = "authors")
@Data
public class Author implements Serializable {
    @Id
    @Column(name = "author_id", nullable = false)
    private Long id;

    @Column(name = "author_name")
    private String name;

    @ManyToMany(fetch = FetchType.LAZY,
        cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
    @JoinTable(name = "author_x_book",
        joinColumns = @JoinColumn(name = "author_id", referencedColumnName = "author_id"),
        inverseJoinColumns = @JoinColumn(name = "book_id", referencedColumnName = "book_id"))
    private List<Book> books;
}


@Entity
@Table(name = "books")
@Data
public class Book implements Serializable {
    @Id
    @Column(name = "book_id", nullable = false)
    private Long id;

    @Column(name = "book_name")
    private String name;

    @ManyToMany(mappedBy = "books", fetch = FetchType.EAGER,
        cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
    private List<Author> authors;
}

Я пытаюсь удалить только запись в author_x_book- то есть удалить связь между конкретной книгой и конкретным автором.Я не собираюсь удалять ни автора, ни книгу, поскольку у книги могут быть другие авторы, а у автора могут быть другие книги.

Я пытался удалить автора из Book.authors и книгу из AuthorЗатем книги сохраняются как в книге, так и в авторе.

@Transactional
public void deleteAssociation(String authorName, String bookName)
{
    Author author = authorRepository.findFirstByName(authorName);
    Book book = bookRepository.findFirstByName(bookName);
    deleteAssociation(author, book);
}

private void deleteAssociation(Author author, Book book) {
    book.getAuthors().remove(author);
    author.getBooks().remove(book);
    authorRepository.save(author);
    bookRepository.save(book);
}

Не работает.Он пытается удалить все авторские ассоциации со всеми его книгами.Затем он пытается добавить эту связь обратно.Журналы Sql:

delete 
from
    "public"."author_x_book" 
where
    "author_id"=?

insert 
into
    "public"."author_x_book" ("author_id", "book_id") 
values
    (?, ?)

Затем я создал сущность AuthorXBook с @EmbeddedId и AuthorXBookRepository.

@Data
@Entity
@Table(name = "author_x_book")
public class AuthorXBook implements Serializable {
    @EmbeddedId
    private AuthorXBookId id;

    @Data
    @Embeddable
    public static class AuthorXBookId implements Serializable {
        @Column(name = "author_id", nullable = false)
        private final long authorId;
        @Column(name = "book_id", nullable = false)
        private final long bookId;
    }
}

@Repository
public interface AuthorXBookRepository extends CrudRepository<AuthorXBook, AuthorXBook.AuthorXBookId> {
}

При вызове AuthorXBookRepository.delete (authorXBook):

private void deleteAssociation(Author author, Book book) {
    authorXBookRepository.delete(new AuthorXBook.AuthorXBookId(author.getId(), book.getId()));
    book.getAuthors().remove(author);
    author.getBooks().remove(book);
    authorRepository.save(author);
    bookRepository.save(book);
}

Он выбирает, а не удаляет, а затем удаляет все книги автора и добавляет обратно ассоциацию:

select
    authorxboo0_."author_id" as author_1_20_0_,
    authorxboo0_."book_id" as book_2_20_0_ 
from
    "public"."author_x_book" authorxboo0_ 
where
    authorxboo0_."author_id"=? 
    and authorxboo0_."book_id"=?

delete 
from
    "public"."author_x_book" 
where
    "author_id"=?

insert 
into
    "public"."author_x_book" ("author_id", "book_id") 
values
    (?, ?)

В итоге я создал @Modifying @Query для удаленияассоциация:

@Repository
public interface AuthorXBookRepository extends CrudRepository<AuthorXBook, AuthorXBook.AuthorXBookId> {
    @Modifying
    @Query("delete from #{#entityName} x where x.authorId=:aid and x.bookId=:bid")
    void delete(@Param("aid") long authorId, @Param("bid") long bookId);
}

private void deleteAssociation(Author author, Book book) {
    authorXBookRepository.delete(author.getId(), book.getId());
    book.getAuthors().remove(author);
    author.getBooks().remove(book);
    authorRepository.save(author);
    bookRepository.save(book);
}

и все заработало.Удаляет только ассоциацию.И не пытается добавить его обратно, я думаю, потому что @Modifiable очищает EntityManager.

Итак, два вопроса:

  1. Почему моя первая и вторая попытка не сработала?

  2. Как правильно удалить только ассоциацию «многие ко многим», не удаляя ни одну из сущностей?

Спасибо

...