2012-10-09 34 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"错误消息失败。 我已经访问过的几页,它说我必须调用save,与此错误结束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

有一两件事要的一点是,错误没有在调用q.save(),而它同时呼吁重定向重定向(Action的抛出的时间抛出”秀”,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) 
     } 
    } 
+1

从save()方法的描述:“该对象将除非使用冲洗说法无法立即坚持。”这就是为什么错误只发生在请求结束时。 –

+0

@TiagoFarias你是对的。在调用q.save(flush:true)之后,我在该行得到错误,这里需要注意的是,即使在错误之后,我的数据仍然被保存!此错误只发生,如果标记已经存在意味着“Tag.findByTag(t)”返回 – Sap

回答

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

那么,我的代码上面的工作,但现在它不索引标签和测验!!所以没有搜索结果:) – Sap

+0

行为似乎很随机,它开始工作在一瞬间,但现在调用q.save时同样的错误(flush:true) – Sap

3

既然你做Quiz.get(id),你有一个'连接“的实例,所以你绝对不需要'合并' - 这只是重新连接一个断开的实例。

我觉得你得到了错误的原因是该行:

def qt = QuizTag.findByQuizAndTag(q, tagToAdd) 

QuizTag实例到会话,但Tag tagToAdd = Tag.findByTag(t)已经与会话相关的实例,并且您指定到另一个变量。您现在有两个与会话关联的实例,它们都代表数据库中的同一行,即qttagToAdd(它们具有相同的ID)。这产生了一个模棱两可的情况,并且不允许,因此是错误。

看来你实际上并不需要qt被实例化(如果它不存在,你只能采取行动)。所以,我会建议做一个查询来确定它是否存在(可能是'select count'),而不是实际检索对象实例。这样,你只会有一个对象的副本。

+0

根据你的建议不应该在“编辑”中的新代码应该工作? – Sap

+0

对不起,我不明白你的问题。什么是“编辑中的新代码”? – GreyBeardedGeek

+0

:)我的意思是原文中的编辑区域。在哪里我将变量赋值改为标签tagToAdd = Tag.findByTag(t)?:新标签(tag:t)和def qt = QuizTag.findByQuizAndTag(q,tagToAdd)?:新QuizTag(测验:q,tag:tagToAdd);你不觉得这可能奏效! – Sap

相关问题