Grails 如何知道验证错误的原因

Grails 如何知道验证错误的原因,grails,grails-validation,Grails,Grails Validation,如果由于某种原因保存失败,下面的代码将抛出grails.validation.ValidationException。但结果是一个普遍的错误。如何知道错误的实际原因,以便向用户报告 def addChild(cName,Parent theParent) { println "add child: ${cName}" def theChild = new Child(name:cName,parent:theParent) theChild.save(failOnErr

如果由于某种原因保存失败,下面的代码将抛出grails.validation.ValidationException。但结果是一个普遍的错误。如何知道错误的实际原因,以便向用户报告

 def addChild(cName,Parent theParent) {
    println "add child: ${cName}"
    def theChild = new Child(name:cName,parent:theParent)
    theChild.save(failOnError:true)
    return theChild
}
这是返回的堆栈跟踪。我碰巧知道这是由于违反了唯一的约束而导致的,因为我是故意造成的,但跟踪中没有任何东西表明这是原因,而不是其他约束违反

org.codehaus.groovy.runtime.InvokerInvocationException: grails.validation.ValidationException: Validation Error(s) Occurred During Save

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)

    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:436)

    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:374)

    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)

    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)

    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)

    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)

    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)

    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)

    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)

    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)

    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)

    at java.lang.Thread.run(Thread.java:619)

Caused by: grails.validation.ValidationException: Validation Error(s) Occurred During Save

    at AddRecordsService.addChild(AddRecordsService.groovy:30)

    at AddRecordsService$addChild.callCurrent(Unknown Source)

    at AddRecordsService.addAll(AddRecordsService.groovy:11)

    at AddRecordsService$$FastClassByCGLIB$$e47d68f4.invoke(<generated>)

    at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)

    at AddRecordsService$$EnhancerByCGLIB$$cdfdcc61.addAll(<generated>)

    at AddRecordsService$addAll.call(Unknown Source)

    at AddrecordController$_closure2.doCall(AddrecordController.groovy:14)

    at AddrecordController$_closure2.doCall(AddrecordController.groovy)

    ... 32 more

我认为ValidationException引用了验证失败的对象?如果是,则检查errors属性以获取错误列表

如果没有,您将需要捕获它,然后检查child.errors以查找错误。

当然,save(failOnError:true)方法目前提供的有关是什么验证导致了问题的信息太少。(您真的想要解析控制器中的异常消息吗?)但是,您可以考虑多个替代方案来处理两个不同的问题,事务回滚和通信验证错误信息。 一种替代方法是完全避免数据的持久性。首先,调用child.validate()以查看是否可以保存该孩子。如果没有验证失败,validate()将返回true,因此调用child.save()。如果发生验证错误,它们将记录在孩子的errors对象中。然后,可以检查返回给调用控制器的新创建的子级是否存在错误,或者只在视图中向用户显示

另一种选择是不使用声明性事务;i、 e.在服务上设置static transactional=false。然后,您的代码可以管理事务本身;大概是这样的:

Child.withTransaction { txStatus ->
   try {
     child.save(failOnError:true)
   } catch (ValidationException e) {
     // rollback, but swallow exception, requiring caller to check child for errors
     txStatus.setRollbackOnly()
   }
}
最后,您的问题意味着您希望控制器处理错误信息,例如呈现原始页面,以便用户可以更正条目。由于child是经过验证的,因此在抛出异常(您自己的或ValidationException)时,返回child将不起作用。但是,在save()调用期间,该子级将填充错误。代替传递字符串和父级,然后实例化服务中的子代,您应该考虑实例化调用方中的子并通过引用传递它。然后,当save()失败时,即使保存(failOnError:true)导致ValidationException,也会填充子项的错误。调用方可以捕获ValidationException,然后将子项作为视图模型的一部分传递回


就个人而言,我认为第一种选择(先调用validate())或最后一种选择(在服务外部实例化子项)比手动管理事务更可取。在Grails中,声明性事务管理对于整个服务来说要么全有,要么全无。也就是说,如果您为服务设置了static transactional=false,则必须手动管理服务的每个方法中的所有事务。KISS原则应该在这里应用。

老问题,但如果有人偶然发现它:在服务中,Grails(2.1)习惯用法是调用save(),如果save失败,则抛出ValidationException

 if (!theChild.save()) {
     throw new ValidationException(theChild.errors)
 } 
通常不调用
save(failOnError:true)
。相反,在控制器中,您捕获ValidationException:

try {
    service.addChild(child)
} catch (ValidationException e) {
    errors.allErrors.each {
        // do something with each error code
    }
}

同样的想法,如果你在你的控制器中做所有的工作。在这种情况下,您不需要抛出然后捕获异常。当然,您可以当场处理
子错误。

尝试使用grails命令类进行验证

示例:

class ParentCommand  {
    .....field.....
     ........constraint.....
   }


def addChild(cName,ParentCommand cmd) {
     if(cmd.hasErrors()) {
    render (cmd.errors as JSON).toString();
    return "false";
} 

您收到了什么样的错误消息?谢谢您的回复。这让我做了更好的搜索。看起来这将在1.2RC1中解决
class ParentCommand  {
    .....field.....
     ........constraint.....
   }


def addChild(cName,ParentCommand cmd) {
     if(cmd.hasErrors()) {
    render (cmd.errors as JSON).toString();
    return "false";
}