5

重複の可能性:
Hibernate: 同じ識別子値を持つ別のオブジェクトが既にセッションに関連付けられていました

"a different object with the same identifier value was already associated with the session"エラーメッセージで失敗している Grails のコントローラーに次のコードがあります。私はすでにいくつかのページにアクセスしましたが、"merge"saveを呼び出す前に呼び出す必要があると書かれており、最終的にこのエラーが発生しますProvided id of the wrong type for class com.easytha.QuizTag. Expected: class java.lang.Long, got class org.hibernate.action.DelayedPostInsertIdentifier

grails 検索可能プラグインがこれを引き起こしている可能性があることを誰かが示唆しており、オプションではない私のドメイン クラスから searchable = true を削除する必要があります (以前の記事grails searcheable plugin search in inner hasMany classを参照してください) 。

注意すべきことの 1 つは、q.save() の呼び出し時にエラーがスローされるのではなく、redirect redirect(action:"show",id: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)
        }
    }

- - - - - -編集 - - - - - - - -

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)
        }
    }
4

2 に答える 2

4

あなたがそうしているのでQuiz.get(id)、あなたは「接続された」インスタンスを持っているので、「マージ」する必要はありません - それは切断されたインスタンスを再接続するためだけです。

エラーが発生する理由は、次の行だと思います。

def qt = QuizTag.findByQuizAndTag(q, tagToAdd)

QuizTagインスタンスをセッションにプルしますが、Tag tagToAdd = Tag.findByTag(t)すでにインスタンスをセッションに関連付けており、別の変数に割り当てています。これで、セッションに関連付けられた 2 つのインスタンスができました。どちらもデータベース内の同じ行を表し、qt(tagToAdd同じ ID を持っています)。これはあいまいな状況を引き起こし、許可されていないため、エラーが発生します。

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

于 2012-10-10T00:51:12.687 に答える
0

Grails はデフォルトで、Hibernate プロキシを使用してコレクションを遅延読み込みします。そのため、重複したQuizTagプロキシ (またはプロキシと膨張したオブジェクト) が作成されている可能性があり、それが問題の原因となっています。

次のようなものを試すことができます:

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)
}
于 2012-10-12T18:46:41.820 に答える