【问题标题】:Spring Data: How to automatically remove a child relation when it is removed from the parentSpring Data:从父级中删除子关系时如何自动删除子关系
【发布时间】:2021-10-30 22:44:35
【问题描述】:

我有一个User 实体,它在@OneToOne 关系中拥有一个Character 实体。但是,我希望 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.ALLorphanRemoval = true 选项,因为这些是我读到的与我的请求相关的唯一内容。

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

【问题讨论】:

  • 是双向关系吗?

标签: kotlin spring-data-jpa spring-repositories


【解决方案1】:

需要注意的两件事:

  • 事务性写入模式
  • 一级缓存
@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
}

【讨论】:

  • 在正常的业务逻辑中我是否也需要entityManager.clear().saveAndFlush 还是仅仅为了这里的单元测试?
  • 虽然在正常业务逻辑中可能有强制刷新或清除持久性上下文的原因,但我想说这些是您通常不需要关心的事情。
猜你喜欢
  • 2017-06-29
  • 2016-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多