Данные Spring /Hibernate: отдельный объект передан для сохранения
Я получаю "отдельный объект передан для сохранения", но я не понимаю, как рассматриваемый объект может находиться в отсоединенном состоянии.
Вот сначала некоторый контекст.
два JpaRepository
s для каждого пользователя и роли:
@Repository
interface RoleRepository : JpaRepository<UserRole, Long> {
fun findByName(name: String): UserRole?
}
@Repository
interface BackendUserRepository : JpaRepository<BackendUser, Long> {
fun findByUserName(name: String): BackendUser?
}
В BackendUser
entity - помимо имени - имеет несколько полей, которые не должны иметь отношения к этому вопросу, роль внешнего поля происходит от его базового класса:
abstract class User(
@ManyToOne(fetch = FetchType.LAZY, cascade = arrayOf(CascadeType.ALL), optional = false)
@JoinColumn(referencedColumnName = "name", nullable = false)
var role: UserRole
) : UserDetails {
// ...
}
При запуске приложения я хочу убедиться, что в этом ApplicationRunner существует пользователь-администратор:
@Component
class InitialDataApplicationRunner : ApplicationRunner {
@Autowired
lateinit var roles: RoleRepository
@Autowired
lateinit var users: BackendUserRepository
override fun run(args: ApplicationArguments) {
// some other stuff
createAdminUser()
}
@Transactional
private fun createAdminUser() {
if (users.findByUserName("admin") == null) {
val adminRole = roles.findByName("admin")!!
val adminUser = BackendUser("admin", adminRole
// some more data here
)
users.save(adminUser)
}
}
}
Приложение выдает исключение при запуске и закрывается:
org.hibernate.PersistentObjectException: отдельный объект, переданный для сохранения: my.package.name.user.UserRole
Насколько я понимаю, здесь adminRole
находится в отсоединенном состоянии сразу после извлечения из репозитория.
- Почему он оторван? Я предполагал, что аннотация @Transactional в методе гарантирует, что все происходит в одном контексте постоянства, а этого не должно происходить.
- Как я могу предотвратить это? Есть ли способ без удаления каскадной опции
- Есть ли какой-либо хороший источник информации о том, как spring/jpa и hibernate работают вместе - пока что то, что я нашел, действительно не помогло мне понять концепции в деталях, и как репозитории, кажется, скрывают концепции управления сущностями и сеанса, которые вы найдете при попытке прочитать в спящем режиме.
1 ответ
Поскольку у вас есть @Transactional для частного метода, а также метод, вызываемый из того же класса, транзакция и, следовательно, отдельное состояние для сохранения отсутствуют ( см. Это). Не уверен, можно ли применить @Transactional к run() или к этому классу. В любом случае, возможно, вам следует создать новый класс "Service" с помощью общедоступного метода @Transactional, а затем вызывать эту службу из вашего класса.