2012-10-09 6 views
5

可能性の重複:
Hibernate: different object with the same identifier value was already associated with the sessionGrailsのエラー

私はGrailsの中に私のコントローラで次のコードを持っています"a different object with the same identifier value was already associated with the session"エラーメッセージで失敗しています。 Provided id of the wrong type for class com.easytha.QuizTag. Expected: class java.lang.Long, got class org.hibernate.action.DelayedPostInsertIdentifier

誰かがGrailsの検索可能なプラグインはこれを引き起こしている可能性がありますことを示唆していると私は、検索=真の姿に私のドメインを削除する必要があり、このエラーで終わる私はすでにそれは私がどの保存呼び出す前に"merge"を呼び出さなければならないことを述べているいくつかのページを訪問しました(前の投稿を参照してください。grails searcheable plugin search in inner hasMany class

qsave()の呼び出し時にエラーがスローされるのではなく、リダイレクトリダイレクト(action: " show "、id:id)!!

提案がありますか?あなたがQuiz.get(id)を行うので

def addTags(String tags,Long id){ 
     if(tags){ 
      String[] strTags = tags.split(","); 
      Quiz q = Quiz.get(id)   
      for(String t in strTags){ 
       Tag tagToAdd = Tag.findByTag(t) 

       if(!tagToAdd){ 
        tagToAdd = new Tag(tag:t) 
        tagToAdd.save() 
       } 

       println "---> "+tagToAdd +" Quiz"+q?.id 
       def qt = QuizTag.findByQuizAndTag(q,tagToAdd) 
       if(!qt){ 
        qt = new QuizTag(quiz:q,tag:tagToAdd); 
        q.addToTags(qt) 
       } 

      }   
      q.save()   
      redirect(action:"show",id:id) 
     } 
    } 

----------- EDIT ---------------

Final code that worked with searchable plugin 
     def addTags(String tags,Long id){ 
     if(tags){ 
      String[] strTags = tags.split(","); 
      Quiz q = Quiz.get(id)   
      for(String t in strTags){ 
       if (q.tags.any { QuizTag qt -> qt.tag.tag == t }) { continue; } 
        Tag tagToAdd = Tag.findOrSaveByTag(t); 
        QuizTag qt = new QuizTag(quiz:q,tag:tagToAdd) 
        q.addToTags(qt) 
       }   
      q.save(flush:true)  
      redirect(action:"show",id:id) 
     } 
    } 
+1

あなたのような何かを試みることができる「フラッシュ引数が使用されていない限り、オブジェクトがすぐに永続化されることはありません」そのため、要求が完了したときにのみエラーが発生します。 –

+0

@TiagoFariasあなたは正しいです。 q.save(flush:true)を呼び出した後、その行でエラーが発生します。エラーが発生してもデータはまだ保存されています。 "Tag.findByTag(t)"が何かを返すという意味のタグが既に存在する場合にのみ発生します。 – Sap

答えて

0

デフォルトでは、GrailsはHibernateプロキシでコレクションを遅延ロードします。そのため、重複するQuizTagのプロキシ(またはプロキシと膨張したオブジェクト)が作成されている可能性があります。 save()メソッドの説明から

Quiz q = Quiz.get(id)   
for(String t in strTags){ 
    // Check if the tag is already joined to this quiz and 
    // skip a dynamic finder load later 
    if (q.tags.any { QuizTag qt -> qt.tag.tag == t }) { continue; } 
    // Find or create-save the tag to join 
    Tag tagToAdd = Tag.findOrSaveByTag(t); 
    QuizTag qt = new QuizTag(quiz:q,tag:tagToAdd) 
    qt.save() 
    q.addToTags(qt) 
} 
+0

私のコードはうまくいきましたが、今ではタグとクイズのインデックスには登録されていませんので、検索結果は表示されません:) – Sap

+0

この動作は非常にランダムなように見えますが、 q.saveを呼び出すときと同じエラー(flush:true) – Sap

3

、あなたが持っています "あなたは間違いなく「マージ」する必要はありません。それは、切断されたインスタンスを再接続するためだけです。

私はあなたがエラーを取得している理由はラインということであると思う:

def qt = QuizTag.findByQuizAndTag(q, tagToAdd) 

がセッションにQuizTagインスタンスを引っ張るが、Tag tagToAdd = Tag.findByTag(t)がすでにセッションにインスタンスが関連付けられている、とあなたが割り当てます別の変数に変更します。これで、セッションに関連付けられた2つのインスタンス(データベース内の同じ行を表す)(qttagToAdd)(同じIDを持つ)が作成されました。これにより、あいまいな状況が発生し、許可されないため、エラーになります。

実際にqtをインスタンス化する必要はないようです(存在しない場合にのみアクションを実行します)。したがって、実際にオブジェクトインスタンスを取得する代わりに、クエリが存在するかどうかを調べる(おそらく 'select count')ことをお勧めします。そうすれば、オブジェクトのコピーを1つしか持てません。

+0

"EDIT"の新しいコードを使用しないでください。 – Sap

+0

申し訳ありませんが、私はあなたの質問を理解していません。 「EDITの新しいコード」とは何ですか? – GreyBeardedGeek

+0

:)元の投稿の編集された領域を意味します。変数割り当てをTagに変更した場所tagToAdd = Tag.findByTag(t)?:新しいタグ(タグ:t)とdef qt = QuizTag.findByQuizAndTag(q、tagToAdd)?:新しいQuizTag(クイズ:q、tag:tagToAdd);それがうまくいったとは思わない? – Sap

関連する問題