Я кое-что выяснил, как удалить только ассоциацию «многие ко многим», не удаляя ни одну из сущностей, и все, что я нашел, это учебные пособия или примеры того, как удалить одну из сущностей без каскадного удаления в другую сущность или в другую.вся таблица (при использовании 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.
Итак, два вопроса:
Почему моя первая и вторая попытка не сработала?
Как правильно удалить только ассоциацию «многие ко многим», не удаляя ни одну из сущностей?
Спасибо