问题
I have one-directional related entities:
@Entity
public class Book {
private String isbn;
}
@Entity
private class Recommentation {
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "book_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
private Book book;
}
And the following test:
@RunWith(SpringRunner.class)
@DataJpaTest
public class BookRepositoryTest {
@Autowired
private TestEntityManager testEntityManager;
@Autowired
private BookRepository bookRepository;
@Test
public void delete() {
// given
String isbn = "isbn-1";
Book book = new Book();
book.setIsbn(isbn);
testEntityManager.persist(book);
Recommendation recommendation = new Recommendation();
recommendation.setBook(book);
testEntityManager.persist(recommendation);
// when
bookRepository.deleteBookByIsbn(book.getIsbn());
// then
assertThat(testEntityManager.find(Book.class, book.getId())).isNull();
assertThat(testEntityManager.find(Recommendation.class, recommendation.getId())).isNull();
}
}
@OnDelete(action = OnDeleteAction.CASCADE)
works perfectly well when this code is invoked not from test but in the test I get exception that recommendation isn't deleted by book.
Also I try to get any info from sql logged for hibernate queries and I can't see any delete
statements for this test.
I don't want to use bidirectional linking for entities and just try to understand how to solve this concrete issue or debug it somehow.
回答1:
@ManyToOne#cascade
@ManyToOne(optional = false, cascade = CascadeType.ALL)
@JoinColumn(name = "book_id", nullable = false)
private Book book;
EDIT 1:
@ManyToOne(optional = false)
@JoinColumn(name = "book_id",
nullable = false,
foreignKey = @ForeignKey(
foreignKeyDefinition = "FOREIGN KEY (book_id) REFERENCES book(id) ON DELETE CASCADE"
)
)
private Book book;
The following approach should do the trick in case you don't want bi-directional mappings and your schema is created from your entites.
In case you create schema from SQL you can also create such a foreign key but in your script.
This approach also expects only one delete query to be executed.
回答2:
A couple of points to note:
Firstly, as far as I am aware @OnDelete(action = OnDeleteAction.CASCADE)
only affects DDL generation i.e. the FK is created in the database with the on delete cascade
clause. You are then delegating the cacading delete to the database and if you are not having Hibernate generate the schema then this annotation will have no effect. As the cascading delete is delegated to the database you will not then see any SQL delete statements being executed by Hibernate.
Secondly, in your test, you are deleting the entity using a JPQL query:
bookRepository.deleteBookByIsbn(book.getIsbn());
rather than by using entityManager.remove(e)
(via your repository's delete(e)
method).
The result of this is that even if you were to apply the JPA CacadeType.DELETE
to the association the delete operation would not cascade as bulk JPQL update/delete queries do not cacade.
See further on this point here:
JPA delete all entites works strange
来源:https://stackoverflow.com/questions/56583707/hibernate-ondelete-cascade-in-test-doesnt-work