Как узнать причину ошибки валидации - PullRequest
2 голосов
/ 29 октября 2009

Следующий код вызовет исключение 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

Обновление

Хорошо, похоже, что, по крайней мере, пока, единственный способ заставить транзакцию откатиться и выяснить, что вызвало ошибку, это проверить, не удалось ли сохранить файл, получить failobject.errors и вызвать исключение RuntimeException. Но теперь, как вы передаете ошибки обратно вызывающему контроллеру? Следующее не работает.

   def addChild(cName,Parent theParent) {
        println "add child: ${cName}"
        def theChild = new Child(name:cName,parent:theParent)

       //theChild.save(failOnError:true)
       //theChild.save()


        if(!theChild.save()){
            println theChild.errors
             throw new RuntimeException(theChild.errors)
            //throw new RuntimeException('unable to save child')
        } 


        return theChild
    }

Ответы [ 4 ]

2 голосов
/ 14 января 2013

Старый вопрос, но если кто-то наткнулся на него: в сервисе идиома Grails (2.1) должна вызвать save () и вызвать исключение ValidationException, если save не удалось.

 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
    }
}

Та же идея, если вы делаете всю работу на вашем контроллере. В этом случае вам не нужно бросать, а затем поймать исключение, конечно, вы можете обработать child.errors на месте.

0 голосов
/ 28 января 2014

Попробуйте использовать класс команды grails для проверки ОБРАТНО ЗДЕСЬ

пример:

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


def addChild(cName,ParentCommand cmd) {
     if(cmd.hasErrors()) {
    render (cmd.errors as JSON).toString();
    return "false";
} 
0 голосов
/ 30 октября 2009

Конечно, подход save (failOnError: true) в настоящее время дает слишком мало информации о том, какие проверки вызвали проблему. (Вы действительно хотите анализировать сообщения об исключениях в контроллере в любом случае?) Однако существует несколько альтернатив, которые вы могли бы рассмотреть для решения двух разных проблем, отката транзакции и передачи информации об ошибке проверки.

Одной из альтернатив является полное отсутствие сохранения данных. Во-первых, вызовите Child.validate (), чтобы увидеть, можно ли сохранить ребенка. Если ни одна валидация не удалась, validate () возвращает true, поэтому вызовите theChild.save (). При возникновении ошибок валидации они будут записаны в объекте ошибок в Child. Вновь созданный дочерний элемент, возвращенный вызывающему контроллеру, затем может быть проверен на наличие ошибок или просто отображен пользователю в представлении.

Другая альтернатива - не использовать декларативные транзакции; т.е. установить статическую транзакцию = 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()
   }
}

Наконец, ваш вопрос подразумевает, что вы хотите, чтобы контроллер что-то делал с информацией об ошибках, например, отображал исходную страницу, чтобы пользователь мог исправить записи. Так как проверяется ребенок, возвращение потомка не будет работать, когда выдается исключение (ваше или ValidationException). Однако у дочернего элемента будут ошибки, заполняемые во время вызова save (). Вместо того, чтобы передавать String и Parent, а затем создавать экземпляр Child в сервисе, вы должны рассмотреть создание экземпляра Child в вызывающей стороне и передать его по ссылке. Затем, когда save () завершается ошибкой, дочерние ошибки будут заполняться, даже если save (failOnError: true) приводит к ValidationException. Вызывающая сторона может перехватить исключение ValidationException и затем передать дочерний элемент как часть модели для представления.

Лично я думаю, что первая альтернатива (сначала вызовите validate ()) или последняя (создание дочернего объекта вне службы) предпочтительнее, чем управление транзакциями вручную. В Grails декларативное управление транзакциями - это все или ничего для всего сервиса. То есть, если вы установите статические транзакции = false для службы, вам придется вручную управлять всеми транзакциями в каждом методе службы. Принцип KISS должен применяться здесь.

0 голосов
/ 29 октября 2009

Я думаю, что ValidationException имеет ссылку на объект, который не прошел проверку?Если это так, проверьте свойство ошибок для списка ошибок.

Если нет, то вам нужно будет его перехватить, а затем проверить ошибки на наличие ошибок.

...