2012-10-09 4 views
5

가능한 중복 :
Hibernate: different object with the same identifier value was already associated with the sessionGrails의 오류 "동일한 식별자 값이 다른 개체가 이미 세션과 관련이 있었다"

I 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의 검색 플러그인이 원인이 될 수 있으며 내가 검색 = 진정한 형태로 내 도메인을 제거해야한다고 제안했다이 오류와 함께 종료되는 save()를 호출하기 전에 "merge"를 호출 할 필요가 있다고 말한다 곳 는 이미 몇 페이지를 방문한 (이전 게시물을 참조하십시오. grails searcheable plugin search in inner hasMany class)

가리키는 한 가지 중요한 점은 q.save()를 호출 할 때 오류가 발생하지 않고 리디렉션 리디렉션 (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) 
     } 
    } 

----------- 편집 ---------------

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 개의 프록시 (또는 프록시 및 비정상적으로 생성 된 개체)가 생성되어 문제를 일으킬 수 있습니다. 저장() 메소드의 설명에서

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) 이미 세션과 인스턴스 관련 지을 수 있고, 당신은 할당된다 다른 변수로. 이제는 세션에 연결된 두 개의 인스턴스가 있습니다. 둘 다 데이터베이스의 동일한 행인 과 tagToAdd (동일한 ID를 가짐)을 나타냅니다. 이것은 모호한 상황을 만들어 내며 허용되지 않으므로 오류가 발생합니다.

실제적으로 qt을 인스턴스화 할 필요가없는 것처럼 보입니다 (존재하지 않는 경우에만 조치를 취함). 그래서, 개체 인스턴스를 실제로 검색하는 대신 쿼리가 존재하는지 (아마도 'select count') 있는지 확인하는 것이 좋습니다. 이렇게하면 개체 복사본을 하나만 만들 수 있습니다.

+0

제안 사항에 따라 "EDIT"의 새 코드가 작동해서는 안됩니까? – Sap

+0

죄송합니다. 질문을 이해할 수 없습니다. "EDIT의 새 코드"란 무엇입니까? – GreyBeardedGeek

+0

:) 원래 게시물의 편집 된 영역을 의미합니다. 변수 할당을 Tag로 변경 한 곳 tagToAdd = Tag.findByTag (t) ?: 새 태그 (태그 : t) 및 def qt = QuizTag.findByQuizAndTag (q, tagToAdd) ?: 새로운 QuizTag (퀴즈 : q, tag : tagToAdd); 그게 효과가 있다고 생각하지 않아! – Sap