测试中的Hibernate OnDelete级联不起作用

时间:2019-06-13 15:18:32

标签: hibernate spring-boot jpa spring-data-jpa spring-test

我有一个单向相关实体:

dfc = dict() 
mydict = {1: 6, 2: 4,3: 10, 4: 7, 5: 3}
for i, (k, v) in enumerate(mydict.items()):
    dfc[(i)] = v
    print("index: {}, key: {}, value: {}".format(i, k, v))      

for i in range(0,5,1):
   result[i] = dfc[i] * dfc[i+1]

以及以下测试:

  File "<ipython-input-139-b31501e8f8af>", line 2, in <module>
    result[i] = dfc[i] * dfc[i+1]

KeyError: 5

@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; } 在不是从测试中调用此代码时效果很好,但是在测试中我得到例外,即书未删除推荐。

此外,我尝试从SQL记录以获取有关休眠查询的任何信息,但此测试我看不到任何@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(); } } 语句。

我不想为实体使用双向链接,而只是想了解如何解决这个具体问题或以某种方式对其进行调试。

2 个答案:

答案 0 :(得分:2)

需要注意的几点:

首先,据我所知@OnDelete(action = OnDeleteAction.CASCADE)仅影响DDL的生成,即FK是使用on delete cascade子句在数据库中创建的。然后,您将级联删除操作委派给数据库,如果您没有让Hibernate生成架构,则此注释将无效。由于将级联删除委托给数据库,您将看不到Hibernate正在执行的任何SQL删除语句。

第二,在测试中,您正在使用JPQL查询删除实体:

bookRepository.deleteBookByIsbn(book.getIsbn());

而不是使用entityManager.remove(e)(通过存储库的delete(e)方法)。

其结果是,即使您将JPA CacadeType.DELETE应用于关联,由于批量JPQL更新/删除查询也不会自动执行,因此删除操作不会级联。< / p>

在此处进一步了解这一点:

JPA delete all entites works strange

答案 1 :(得分:1)

@ManyToOne#cascade

@ManyToOne(optional = false, cascade = CascadeType.ALL)
@JoinColumn(name = "book_id", nullable = false)
private Book book;

编辑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;

如果您不希望进行双向映射,而模式是由实体创建的,则以下方法可以解决问题。

如果您通过SQL创建架构,则也可以在脚本中创建这样的外键。

这种方法还希望仅执行一个删除查询。