7

これについてはすでに検索しましたが、何が間違っているのかまだわかりません。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

また、flush:true を使用する場合

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()です。何か案は?

ありがとう

4

2 に答える 2

7

オブジェクトが実際にデータベースに永続化されるタイミングを誤解しています。オブジェクトは、呼び出したときに永続化されません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
  }
}
于 2012-11-28T00:55:16.593 に答える
2

その save(flush:true) はエラーをスローする必要があります

それは真実ではない。 save(failOnError: true)例外がスローされます。

コードに問題はなく、表示されている動作にも問題はありません。フラッシュを呼び出さないことによって; save()、実際の挿入が行われる前に、生成された ID にアクセスしようとしています。それがヌルである理由です。

ただし、フラッシュを強制すると、(場合によっては)休止状態が強制的に書き込まれ、期待する ID が得られます。を呼び出した直後に ID が必要な場合はsave()、 を使用しますsave(flush: true)。それは何も悪いことではありません。

于 2012-11-28T00:44:46.210 に答える