2013-07-31 2 views
1

У меня есть следующий фрагмент кода, который добавляет новый объект в базу данных. Сначала он берет другой объект из БД и добавляет к конечному объекту.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

Ну, эта проблема возникает, когда вы инициализируете класс 'new ClassD' с идентификатором или уникальным свойством вручную, когда в сеансе есть еще один. Итак, сначала вы должны попытаться получить эту сущность (это то, что «findOrCreateWhere» делает, но если вы используете идентификатор, вам нужно использовать 'get'), а затем использовать найденный экземпляр или создать новый для обновления. – elias

+0

Привет, я прочитал ваши намеки, и я обновил свой пост. Теперь у меня другая ошибка. Не могли бы вы взглянуть? – ruhungry

0

Посмотрите на AuditLogService. Кажется, что вы выполняете какой-то аудит или безопасность для классов домена (или Hibernate), и для этого требуется контекст безопасности, в то время как вы вызываете этот код за пределами одного.

Кроме того, просто из любопытства, почему вы звоните .merge() на c?

Смежные вопросы