вызов Grails ajax, строка-была-обновлена-или-удалена-другой-транзакцией-или-несохраненным-сопоставлением-значением-была

Я использую Grails 2.3.5, и у меня есть контроллер, который содержит метод ajaxDelete. Этот метод получает имя в виде строки объекта, который я хочу удалить. Я использую службу для удаления объекта, который я вызываю из своего контроллера.

При первом вызове метода службы deleteSvnUser пользователь SVN удаляется, а мой div на странице обновляется предупреждением о том, что пользователь был удален. Во второй раз, когда я удаляю пользователя, я получаю следующую ошибку:

row-was-updated-or-deleted-by-another-transaction-or-unsaved-value-mapping-was...

Я пробовал пару вещей, чтобы обойти это:

  • Добавление аннотации @transactional к моей службе (чего мне не нужно, потому что по умолчанию она должна быть транзакционной).
  • сброс моих удалений (flush:true)
  • Обновление объекта перед его удалением (.refresh)
  • Блокировка объекта при его извлечении (entity.lock(id))

Ничего из вышеперечисленного не сработало. Я не уверен, что еще сделать, чтобы обойти это. Кто-нибудь может помочь? мой код ниже:

Контроллер

class SvnUserController {

def svnUserService  

def ajaxDelete() {

    if (!params.selectedSvnUser) {
        request.error = "The selected Svn User does not exist"
        render(template:"svnUserList", model:[svnUserInstanceList: SvnUser.list(params).sort{it.name}, svnUserInstanceTotal: SvnUser.count()])              
        return
    }

        String outcome = svnUserService.deleteSvnUser(params.selectedSvnUser)

        switch (outcome){

            case "":
                request.message = "Svn User ${params.selectedSvnUser} deleted"
                break

            default: request.error = outcome
        }

    }        

    def svnUsers =  svnUserService.getAllSvnUsers(params)
    render(template:"svnUserList", model:[svnUserInstanceList: svnUsers, svnUserInstanceTotal: svnUsers.size()])
    return
}
}

Услуга

class SvnUserService {

 public String deleteSvnUser(String userName) {

    String outcome = ""

    try {

        SvnUser svnUserInstance = SvnUser.findByName(userName)
        def groups = SvnGroupController.findAllBySvnUserName(userName)

        groups.each { SvnGroup group ->

            group.removeFromSvnUsers(svnUserInstance)
            group.save()
        }

        def userPermissionsList = UserPermission.findAllBySvnUser(svnUserInstance)

        userPermissionsList.each {
            def repoDirectory = it.repositoryDirectory
            repoDirectory.removeFromUserPermissions(it)
            it.delete()
        }

        svnUserInstance.merge()
        svnUserInstance.delete()            
    }
    catch (DataIntegrityViolationException e) {
        outcome = "A error occurred while attempting to delete the Svn User from file."
    }


    return outcome
}

}

Трассировка стека выглядит следующим образом:

Error |
2014-06-10 15:10:07,394 [http-bio-8080-exec-6] ERROR errors.GrailsExceptionResolver  -     StaleObjectStateException occurred when processing request: [POST]  /subzero/svnUser/ajaxDelete - parameters:
selectedSvnUser: ruby2
Row was updated or deleted by another transaction (or unsaved-value mapping was  incorrect): [com.uk.nmi.subzero.SvnGroup#2]. Stacktrace follows:
Message: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.uk.nmi.subzero.SvnGroup#2]
Line | Method
->>   72 | deleteSvnUser in com.uk.nmi.subzero.SvnUserService
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|     87 | ajaxDelete    in com.uk.nmi.subzero.SvnUserController
|    200 | doFilter . .  in grails.plugin.cache.web.filter.PageFragmentCachingFilter
|     63 | doFilter      in grails.plugin.cache.web.filter.AbstractFilter
|   1145 | runWorker . . in java.util.concurrent.ThreadPoolExecutor
|    615 | run           in java.util.concurrent.ThreadPoolExecutor$Worker
^    744 | run . . . . . in java.lang.Thread

person user3065675    schedule 10.06.2014    source источник


Ответы (1)


Я не вижу никаких проблем с вашим кодом. Grails должен нормально обрабатывать транзакции.

Если ваше сопоставление объектов настроено правильно, вызов svnUserInstance.delete() должен также удалить дочерние объекты, поэтому я не думаю, что вам даже нужны строки между svnUserInstance = SvnUser.findByName(userName) и удалением.

Как вы вызываете ajaxDelete? Есть ли шанс, что он вызывается неправильно во второй раз?

person anorakgirl    schedule 11.06.2014
comment
Да, ты прав. Оказывается, мой второй вызов ajax вызывал метод контроллера дважды, потому что он снова добавлял событие click(), а не заменял событие первого щелчка вторым событием щелчка. При втором вызове метода контроллера возникла ошибка, поскольку пользователь был удален при первом вызове. - person user3065675; 11.06.2014