Grails的。 标识调用save后为空(Grails. Id is null after ca

2019-08-03 06:17发布

我已经搜索这个,但还是无法弄清楚我在做什么错。 打完电话后save()域对象idnull

我读过,如果保存对象时,有一个问题,它会发生,并且save(flush:true) ,如果是这样的话应该抛出一个错误,但它不是。 看看我的代码和输出:

def pic = new Picture(title:'XX', path:"XXX")
album.addToPictures(pic).save()
if(pic.validate())
   println "no errors. New id: " + pic.id
else
   println "with errors"

输出:

no errors. New id: null

而在使用冲洗时:真

def pic = new Picture(title:'XX', path:"XXX")
album.addToPictures(pic).save(flush:true)
if(pic.validate())
   println "no errors. New id: " + pic.id
else
   println "with errors"

输出:

no errors. New id: 17

正如你所看到的,有没有创建对象的任何错误,我应该能够得到id只调用后,对象的save() 有任何想法吗?

谢谢

Answer 1:

你是误会当一个对象实际上得到持久化到数据库的时间。 一个对象没有得到,当你调用持续obj.save()当发生以下情况先发生者为准,它就会坚持:

  • 其中保存(交易)被称为承诺
  • 其中保存Hibernate的Session()被调用关闭

事务可以明确地启动

SomeDomainClass.withTransaction {
  // code in here runs within a transaction
}

通常情况下,交易也被隐式开始每次调用一个服务方法

class MyService {

  void doSomething () {
    // code in here runs within a transaction
  }  
}

如果你不明确或含蓄地使用事务,保存的对象得到坚持,当Hibernate的Session关闭,这是(大致)的HTTP请求完成时。

但是,如果你调用someObject.save(flush: true)你告诉Hibernate来坚持立即对象,这是为什么

album.addToPictures(pic).save(flush: true)

分配ID的Picture的实例,但

album.addToPictures(pic).save()

当包封会话/交易结束后就会只分配了ID /承诺

更新

Futher您的意见

问题是,我想使用的ID作为文件我需要保存的名称的一部分。 怎么样,如果我得到一个保存文件时出错? 我应该使用一个明确的事务,并回滚?

是的,使用一个明确的交易,并保存该文件一旦你确定对象已被成功地坚持着,回滚事务,如果持续失败

def pic = new Picture(title:'XX', path:"XXX")

Picture.withTransaction { TransactionStatus status ->        

  try {
    album.addToPictures(pic).save()

  } catch(ex) {
    status.setRollbackOnly()
    throw ex
  }
}

// At this point you can be sure pic has been persisted, so use pic.id to save the file

更新2

而且您的意见

我不想保存该文件一旦我敢肯定,对象已经成功地坚持着,但相反的,我想坚持的目标,一旦该文件已被成功保存。 所以,我要重新制定我的问题是“是否有配置Grails的,这样我可以知道那将被分配到新对象之前,该对象被有效保存在数据库中的ID的方法吗?”

你已经知道,

album.addToPictures(pic).save(flush:true)

会为您提供的ID Picture实例,因此,如果你这样做在一个事务中,你可以得到的ID,而无需实际提交事务。 但是,我认为,如果你使用的是使用序列数据库(甲骨文,Postgres的)这只会工作。 像下面这样的东西应该工作

Picture.withTransaction { TransactionStatus status ->        

  try {
    def pic = new Picture(title:'XX', path:"XXX")  
    album.addToPictures(pic).save(flush: true)

    // pic.id should now be assigned, so save the file. I'm assuming an
    // an exception will be thrown if saving the file fails

  } catch(ex) {
    // you may also want to try rolling back the file save here, i.e. delete it
    status.setRollbackOnly()
    throw ex
  }
}


Answer 2:

并保存(冲洗:真)应该抛出一个错误

这不是真的。 save(failOnError: true)将导致异常被抛出。

没有什么是你的代码错误,也不是什么错,你所看到的行为。 如果不调用flush; save()你想真正的插入发生之前访问生成的ID。 这就是为什么它是空的。

然而,迫使冲洗意志(有时)强制Hibernate来写,然后给你你期待的ID。 如果您需要的ID调用后立即save()使用save(flush: true) 。 没有什么不妥。



文章来源: Grails. Id is null after calling save