Данные Spring /Hibernate: отдельный объект передан для сохранения

Я получаю "отдельный объект передан для сохранения", но я не понимаю, как рассматриваемый объект может находиться в отсоединенном состоянии.
Вот сначала некоторый контекст.

два JpaRepositorys для каждого пользователя и роли:

@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, а затем вызывать эту службу из вашего класса.

Другие вопросы по тегам