Данные Spring / Hibernate: отдельный объект передан для сохранения - PullRequest
0 голосов
/ 13 июля 2020

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

два 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 - помимо имени - имеет несколько полей, которые не должны быть связаны на этот вопрос роль внешнего поля происходит от его базового класса:

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 и спящий режим взаимодействуют вместе - до сих пор все, что я нашел, действительно не помогло мне подробно понять концепции , и как кажется, что репозитории скрывают концепции управления сущностями и сеанса, которые вы обнаруживаете при попытке чтения в спящем режиме.

1 Ответ

1 голос
/ 13 июля 2020

Поскольку у вас есть @Transactional для частного метода, а также метод, вызываемый из того же класса, нет транзакции и, следовательно, отдельного состояния для сохранения ( см. Это ). Не уверен, можно ли применить @Transactional к run () или к этому классу. В любом случае, возможно, вам следует создать новый класс «Service» с помощью метода publi c @Transactional, а затем вызвать эту службу из вашего класса.

...