Spring 数据:如何在从父关系中删除子关系时自动删除子关系
Spring Data: How to automatically remove a child relation when it is removed from the parent
我有一个 User
实体,它在 @OneToOne
关系中拥有一个 Character
实体。但是我希望他 Character
记录在与 User
实体分离后立即被删除。
这是我的 User.kt
实体 class:
// 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.ALL
和 orphanRemoval = true
选项,因为这是我读到的唯一与我的请求相关的内容。
我在单元测试中所做的是创建一个用户和角色实例。然后将角色实例添加到用户并通过 UserRepository
保存用户。感谢 CascadeType.ALL
角色实例将自动保存。现在,当 从用户那里删除 角色时,我想反过来做同样的事情。然而,正如您在单元测试的最后一行中看到的那样,这并不像预期的那样工作
需要注意两点:
- 事务后写模式
- 一级缓存
@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
}
我有一个 User
实体,它在 @OneToOne
关系中拥有一个 Character
实体。但是我希望他 Character
记录在与 User
实体分离后立即被删除。
这是我的 User.kt
实体 class:
// 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.ALL
和 orphanRemoval = true
选项,因为这是我读到的唯一与我的请求相关的内容。
我在单元测试中所做的是创建一个用户和角色实例。然后将角色实例添加到用户并通过 UserRepository
保存用户。感谢 CascadeType.ALL
角色实例将自动保存。现在,当 从用户那里删除 角色时,我想反过来做同样的事情。然而,正如您在单元测试的最后一行中看到的那样,这并不像预期的那样工作
需要注意两点:
- 事务后写模式
- 一级缓存
@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
}