我有一个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.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
}