Grails控制器无论如何都会保存域项

时间:2014-06-10 10:23:23

标签: hibernate grails grails-controller

使用Grails 2.3.9

在控制器中,我会进行一些检查,并且在使用自定义错误响应返回失败时。这是一段代码:

def update() {
    def instance = Group.get(params.groupId)
    instance.properies = params

    if (instance.hasErrors()) {
        // going through here: instance is not saved
        respond instance.errors, view:'edit'
        return
    }

    // do custom checks
    if(checksFailed) {
        // instance is saved anyways :(
        instance.discard()
        response.sendError(response.SC_CONFLICT)
        return
    }

    instance.save flush:true
    // ... respond success
}

检查失败时,我会根据需要返回错误响应。但是,实例仍会保存(未达到instance.save)。如何让Grails / Hibernate知道不保存这个实例?

另一种方法可能是将实例与Hibernate会话断开连接。我怎么能在Grails中做到这一点?

更新:在域实例为scaffolded的控制器中,instance.discard()技巧有效:

def update(Group groupInstance) {
    if (groupInstance.hasErrors()) {
        // going through here: instance is not saved
        respond instance.errors, view:'edit'
        return
    }

    // do custom checks
    if(checksFailed) {
        // instance is not saved
        groupInstance.discard()
        response.sendError(response.SC_CONFLICT)
        return
    }

    groupInstance.save flush:true
    // ... respond success
}

我发现很难理解为什么它在一个案例中起作用而在另一个案例中起作用。

1 个答案:

答案 0 :(得分:3)

执行此操作的最佳方法是不使用discard(),而是使用数据库的事务和本机事务功能。我建议将逻辑移到服务中(将控制器流程代码与应用程序的逻辑分开。例如:

class GroupService {
   @Transactional
   void updateBook(params) {
       ....
       // do custom checks
       if(checksFailed) {
          status.setRollbackOnly() // rollback transaction        
       }
       else {
           instance.save flush:true
       }
   }
}

您可以在事务状态上调用setRollbackOnly或抛出运行时异常。

注意,如果使用异常,它们可能很昂贵,因此最好创建一个自定义异常类型,例如GroupUpdateException,并覆盖fillInStackTrace以填充堆栈跟踪,从而降低异常成本。见Why is Throwable.fillInStackTrace() method public? Why would someone use it?