我做了一些深入探讨如何在不删除任何实体的情况下仅删除多对多关联,并且我发现的所有内容都是关于如何删除其中一个实体而没有级联删除到另一个实体或者整个表(使用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实体:
@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.books中删除该书,然后保留书籍和作者。
@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
(?, ?)
然后我用@EmbeddedId和AuthorXBookRepository创建了一个AuthorXBook实体。
@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。
所以,有两个问题:
为什么我的第一次和第二次尝试都不起作用?
在不删除任何实体的情况下,只删除多对多关联的正确方法是什么?
谢谢