2012-02-09 14 views
0

我的用户正在上传csv或xls或其他任何内容,每行都将成为我保存的域对象的实例。如果任何一行失败,我希望整个事情回滚,但我也想为任何后来失败的行返回错误。让我们做一个例子:Grails:如何在事务已经失败时继续验证时如何构建事务

域类:

MyDomainClass{ 
    String fieldOne 
    BigDecimal fieldTwo 
} 

输入:

ThisLineWorks,4.4 
ThisLineFails,BecauseOfThis 
How would I also get an error, for this line as well considering the last one would have rolled back the transaction already? 

幻想输出:

OK|ThisLineWorks,4.4 
field 2 isn't a number|ThisLineFails,BecauseOfThis 
field 2 isn't a number|How would I also get an error, for this line as well considering the last one would have rolled back the transaction already? 

回答

2

您可以验证对象而无需保存它们:(http://grails.org/doc/2.0.x/guide/validation.html#validatingConstraints)。因此,在服务中,您可以创建所有对象,然后验证所有对象,然后保存所有对象。类似的东西来:

def serviceMethod(data) { 
    def listOfObjects = createObjectsFromData(data) 
    listOfObjects*.validate() 
    def anErrorOccurred = listOfObjects.find {it.hasErrors()} != null 
    if(anErrorOccurred) { 
     return listOfObjects 
    } 
    listOfObjects*.save(validate: false) //you could use the validate:false or leave it out. I figure since we've already validated that you could do without re-validating. 
} 

这样你就可以收集所有你的错误,而不是担心回滚事务。这个设置的问题是您将创建N个对象并保留所有对象。如果您的文件长度超过10万行(稍微有教育意义的猜测会让您开始受到影响),那么这可能会导致一些性能问题。如果你不喜欢,你可以手工处理的事务上面的方法: (http://grails.org/doc/2.0.x/ref/Domain%20Classes/withTransaction.html

def serviceMethod(data) { 
    MyDomainClass.withTransaction { status -> 
     def listOfObjects = [] 
     data.each { 
      def domainObject = createObjectFromData(it) 
      lisOfObjects << domainObject.save() 
     } 
     def anErrorOccurred = lisOfObjects.find {it.hasErrors()} != null 
     if(anErrorOccurred) { 
      status.setRollbackOnly() //will roll back all of the transactions surrounded by the .withTransaction {} 
     } 
    } 
} 

你还在抓着所有对象的位置(因为要检索发生的所有错误)。我可以想到的一种避免保留所有对象的方法是逐个创建对象,并在适用时逐一验证它们是否将错误添加到列表中,但是必须重新创建所有对象当他们都通过验证时,这看起来效率不高。

+0

http://naleid.com/blog/2009/10/01/batch-import-performance-with-grails-and-mysql/似乎表明100k你是真的痛苦和10k左右,你开始看到斗争。这就是说,我认为这个解决方案对我来说工作得很好:) – Mikey 2012-03-02 04:55:42

+0

然后,也许Grails在这个问题上前进了一步......直到现在,我的源码上没有看到日期。 – Mikey 2012-03-02 04:56:30

2

这里就是我想:

1 。如果全部清除,则设置一个标志,标志ALL CLEAR并手动完成交易。

2。在单独的事务中提交每一行,以捕获失败行的错误并跳过失败。

相关问题