5

可能重复:
休眠:具有相同标识符值的不同对象已与会话关联

我在 Grails 的控制器中有以下代码失败并"a different object with the same identifier value was already associated with the session"显示错误消息。我已经访问了几个页面,上面说我必须"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

需要指出的一点是,在调用 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)已经将该实例与会话相关联,并且您正在分配给另一个变量。您现在有两个与会话关联的实例,它们都表示数据库中的同一行,qt并且tagToAdd(它们具有相同的 id)。这会产生模棱两可的情况,并且是不允许的,因此会出现错误。

看来您实际上并不需要qt被实例化(只有在它不存在时才采取行动)。因此,我建议进行查询以查明它是否存在(可能是' select count'),而不是实际检索对象实例。这样,您将只有一个对象的副本。

于 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 回答