首页 > 解决方案 > Spring Data:从父级中删除子关系时如何自动删除子关系

问题描述

我有一个实体,它在关系User中拥有一个Character实体。@OneToOne但是,我希望他的记录在与实体Character分离后立即被删除。User

这是我的User.kt实体类:

// User.kt

@Entity
class User(
    @Id
    var id: String,
    var email: String,
    @OneToOne(cascade = [CascadeType.ALL], orphanRemoval = true)
    var character: Character?,
    var isAdmin: Boolean
) { // ... }

这是我为测试此行为而编写的单元测试:

// UserRepositoryTest.kt

@Test
fun `should remove orphan character entity when being removed from user entity`() {
    val user = UserTestTemplate.testUser()
    val character = CharacterTestTemplate.testCharacter()

    user.character = character
    userRepository.save(user)

    user.character = null
    userRepository.save(user)

    val actual = userRepository.findById(user.id).orElse(null)

    assertThat(actual).isNotNull()
    assertThat(actual.character).isNull()

    val savedCharacter = characterRepository.findById(character.id)
    assertThat(savedCharacter.get()).isNull() // fails
}

我添加了CascadeType.ALLandorphanRemoval = true选项,因为这些是我读到的与我的请求相关的唯一内容。

我在单元测试中所做的是创建用户和角色实例。然后将角色实例添加到用户并通过UserRepository. 由于CascadeType.ALL字符实例将自动保存。现在,当从用户中删除角色时,我想反过来做同样的事情。但是,正如您在单元测试的最后一行中看到的那样,这并没有按预期工作

标签: kotlinspring-data-jpaspring-repositories

解决方案


有两点需要注意:

  • 事务性写入模式
  • 一级缓存
@Test
fun `should remove orphan character entity  entity`() {
    val user = UserTestTemplate.testUser()
    val character = CharacterTestTemplate.testCharacter()

    user.character = character
    userRepository.save(user)

    user.character = null

    //use saveAndFlush here to force immediate DB update
    //otherwise may be deferred until transactional method returns
    userRepository.saveAndFlush(user)

    //clear the persistence context to ensure you will be reading from 
    //the database rather than first level cache
    //entityManager is injected to test via @PersistenceContext annotation
    entityManager.clear();

    //now you are guaranteed a db read reflecting all flushed updates
    val actual = userRepository.findById(user.id).orElse(null)

    assertThat(actual).isNotNull()
    assertThat(actual.character).isNull()

    val savedCharacter = characterRepository.findById(character.id)
    assertThat(savedCharacter.get()).isNull() // fails
}

推荐阅读