Hibernate OnDelete cascade in test doesn't work

一笑奈何 提交于 2020-08-26 08:47:05

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!