Grails“具有相同标识符值的不同对象已与会话关联”错误

时间:2012-10-09 21:38:08

标签: hibernate grails groovy grails-searchable

  

可能重复:
  Hibernate: different object with the same identifier value was already associated with the session

我在Grails中的控制器中有以下代码,但出现"a different object with the same identifier value was already associated with the session"错误消息失败。 我已经访问了几个页面,其中说我必须在调用save之前调用"merge",最后会出现此错误Provided id of the wrong type for class com.easytha.QuizTag. Expected: class java.lang.Long, got class org.hibernate.action.DelayedPostInsertIdentifier

有人建议grails searchable插件可能会导致这种情况,我应该删除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)
        }
    }

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

2 个答案:

答案 0 :(得分:3)

由于您执行了Quiz.get(id),因此您已经连接了'例如,所以你绝对不需要合并' - 仅用于重新连接断开连接的实例。

我认为您收到错误的原因是该行:

def qt = QuizTag.findByQuizAndTag(q, tagToAdd)

QuizTag实例拉入会话,但Tag tagToAdd = Tag.findByTag(t)已将实例与会话相关联,并且您要分配给另一个变量。您现在有两个与会话关联的实例,它们都代表数据库中的同一行qttagToAdd(它们具有相同的ID)。这会产生不明确的情况,因此不允许出现错误。

您似乎实际上并不需要qt进行实例化(如果它不存在,您只会采取行动)。因此,我建议您查询是否存在(可能是' select count'),而不是实际检索对象实例。这样,您只能拥有该对象的一个​​副本。

答案 1 :(得分: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)
}