オブジェクトが実際にデータベースに永続化されるタイミングを誤解しています。オブジェクトは、呼び出したときに永続化されませんobj.save()
。次のいずれかが最初に発生したときに永続化されます。
- save()が呼び出されるトランザクションがコミットされます
- save()が呼び出されるHibernateセッションが閉じられます
トランザクションは、次のコマンドで明示的に開始できます。
SomeDomainClass.withTransaction {
// code in here runs within a transaction
}
通常、トランザクションは、サービスメソッドの呼び出しごとに暗黙的に開始されます
class MyService {
void doSomething () {
// code in here runs within a transaction
}
}
明示的または暗黙的にトランザクションを使用しない場合、保存されたオブジェクトは、Hibernateセッションが閉じたとき、つまり(おおよそ)HTTP要求が完了したときに永続化されます。
ただし、呼び出すsomeObject.save(flush: true)
場合は、オブジェクトをすぐに永続化するようにHibernateに指示しているためです。
album.addToPictures(pic).save(flush: true)
Picture
インスタンスにIDを割り当てますが、
album.addToPictures(pic).save()
囲んでいるセッション/トランザクションが閉じられている/コミットされている場合にのみIDを割り当てます
アップデート
あなたのコメントへのさらなる
問題は、保存する必要のあるファイルの名前の一部として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
あなたのコメントに加えて
オブジェクトが正常に永続化されたことを確認したらファイルを保存したくないのですが、逆に、ファイルが正常に保存されたらオブジェクトを永続化したいと思います。そこで、「オブジェクトがデータベースに効果的に保存される前に、新しいオブジェクトに割り当てられるIDを知ることができるように、Grailsを構成する方法はありますか?」という質問を再定式化します。
あなたはすでにそれを知っています
album.addToPictures(pic).save(flush:true)
インスタンスのIDが提供されるためPicture
、トランザクション内でこれを行うと、実際にトランザクションをコミットしなくてもIDを取得できます。ただし、これは、シーケンスを使用するデータベース(Oracle、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
}
}