2013-07-31 37 views
1

我有以下一段代碼,它將新的對象添加到數據庫。首先它從DB中取出另一個對象並添加到最終對象中。Grails - DuplicateKeyException

我的代碼

  ClassC c = ClassC.findByName(cName) 

      ClassD d = new ClassD(
        name: "WHATEVER", 
        classC: c 
      ) 

      print "AAA\n" 

      ClassC.withTransaction { 
       c = c.merge() 
       // c.save(failOnError: true, flush: true) 
      } 

      print "BBB\n" 

      // ClassD.withTransaction { 
      //  d = d.merge() 
      // } 
      // print "CCC\n" 

      ClassD.withTransaction { 
       d.save(failOnError: true, flush: true) 
      } 

      print "DDD\n" 

幾行我有以下錯誤:

AAA 
BBB 

2013-07-31 13:57:14,279 ERROR JobRunShell - Job DEFAULT.1 threw an unhandled Exception: 
org.springframework.dao.DuplicateKeyException: a different object with the same identifier value was already associated with the session: [xxx.ClassD#15]; nested exception is org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [xxx.ClassD#15] 

你能幫助我嗎?

感謝


ClassC.withTransaction { 
    ClassC c = ClassC.findByName(cName) 

    // find the record with name: "WHATEVER" or create a new one if there is none 
    ClassD d = ClassD.findOrCreateWhere(name: "WHATEVER") 

    c = c.merge() 
    c.addToClassesD(d) // static hasMany = [classesD: ClassD] <-- in ClassC domain 
    c.save(failOnError: true, flush: true) 
} 

誤差從線

c.addToClassesD(d)

java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request. at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) at org.springframework.web.context.request.RequestContextHolder$currentRequestAttributes.call(Unknown Source) at xxx.AuditLogService.getCurrentUser(AuditLogService.groovy:127) at xxx.AuditLogService$getCurrentUser.callStatic(Unknown Source) at xxx.AuditLogService$_closure2.doCall(AuditLogService.groovy:58) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1243) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90) 2013-08-02 09:39:11,110 ERROR ErrorLogger - Job (DEFAULT.1 threw an exception. org.quartz.SchedulerException: Job threw an unhandled exception. at org.quartz.core.JobRunShell.run(JobRunShell.java:224) at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:557) Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request. at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) at org.springframework.web.context.request.RequestContextHolder$currentRequestAttributes.call(Unknown Source) at xxx.AuditLogService.getCurrentUser(AuditLogService.groovy:127) at xxx.AuditLogService$getCurrentUser.callStatic(Unknown Source) at xxx.AuditLogService$_closure2.doCall(AuditLogService.groovy:58) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1243) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)

+1

嘿,夥計!你能在我的答案中嘗試解決方案嗎? – elias

回答

2

你或許應該做這一切只有一個事務中。

至於你得到的錯誤,我假設你有一個名爲unique的設置 - 當已經有一個名字爲「WHATEVER」的記錄時,你會得到這個錯誤。

你可能想要做這樣的事情,而不是:

ClassC.withTransaction { 
    ClassC c = ClassC.findByName(cName) 

    // find the record with name: "WHATEVER" or create a new one if there is none 
    ClassD d = ClassD.findOrCreateWhere(name: "WHATEVER") 

    c = c.merge() 
    d.classC = c 
    d.save(failOnError: true, flush: true) 
} 
+0

嗨!我只是複製了一段我的代碼。在真實的代碼中,沒有「WHATEVER」,但是更復雜的數據,所以不用擔心 - 它總是唯一的。錯誤來自org.hibernate.NonUniqueObjectException – ruhungry

+2

那麼,當您在會話中已經存在另一個時,手動初始化具有id或unique屬性的類'new ClassD'時會發生此問題。所以,你應該試着首先得到這個實體(這就是'findOrCreateWhere'的作用,但是如果你使用一個id,你需要使用'get'),然後使用找到的實例或創建一個新的實例來進行更新。 – elias

+0

嗨,我讀了你的提示,我更新了我的帖子。現在,我有另一個錯誤。你可以看一下嗎? – ruhungry

0

看看AuditLogService。看起來你正在實現對域類(或Hibernate)的某種審計或安全性,而這需要一個安全上下文,而你在這個代碼之外調用這個代碼。

此外,出於好奇,你爲什麼要在c上調用.merge()?