0

I am trying to call a few services in my controllers update method. Unfortunatly this results in a StaleObjectStateException and I dont really know why since I'm "just" calling service-methods which are transactional

Here is the exception:

| Error 2015-06-21 15:43:43,091 [http-bio-8080-exec-7] ERROR errors.GrailsExceptionResolver  - StaleObjectStateException occurred when processing request: [PUT] /time-tracking-backend/projectBooking/update/1 - parameters:
date: struct
duration: 120
date_year: 2015
date_month: 6
project.id: 1
_method: PUT
_action_update: Aktualisieren
comment: jojo
date_day: 21
version: 0
subProject.id: 2
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [projectmanagement.SubProject#2]. Stacktrace follows:
Message: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [projectmanagement.SubProject#2]
    Line | Method
->>   48 | $tt__setActualHours in projectmanagement.ProjectService$$EPGFZqxM
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|    201 | $tt__update         in timemanagement.ProjectBookingController$$EPGFYoBE
|    198 | doFilter . . . . .  in grails.plugin.cache.web.filter.PageFragmentCachingFilter
|     63 | doFilter            in grails.plugin.cache.web.filter.AbstractFilter
|     53 | doFilter . . . . .  in grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter
|    139 | doFilter            in grails.plugin.springsecurity.rest.RestAuthenticationFilter
|     49 | doFilter . . . . .  in grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter
|     82 | doFilter            in grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter
|     80 | doFilter . . . . .  in grails.plugin.springsecurity.rest.RestLogoutFilter
|     82 | doFilter            in com.brandseye.cors.CorsFilter
|   1142 | runWorker . . . . . in java.util.concurrent.ThreadPoolExecutor
|    617 | run                 in java.util.concurrent.ThreadPoolExecutor$Worker
^    745 | run . . . . . . . . in java.lang.Thread
......

.. and the important part in my controllers update method:

if(projectBookingInstance.getPersistentValue("subProject") != projectBookingInstance.subProject
        || projectBookingInstance.getPersistentValue("date") != projectBookingInstance.date){

            ProjectBooking projectBookingToBeUpdated = ProjectBooking.get(projectBookingInstance.id)

            if(projectBookingToBeUpdated != null){

                projectService.deleteActualHours(projectBookingToBeUpdated)

                projectBookingToBeUpdated.delete(flush:true)
                projectService.setActualHours(projectBookingToBeUpdated)
                projectBookingInstance.save(flush:true)
                return
            }
        }

The two service methods:

def deleteActualHours(ProjectBooking projectBookingInstance){

        Project project = projectBookingInstance.project
        SubProject subProject = projectBookingInstance.subProject

        Double duration = projectBookingInstance.duration / 60
        duration = duration.round(2)

        project.actualHours -= duration     
        subProject.actualHours -= duration

        project.save(flush:true)
        subProject.save(flush:true)     
    }


def setActualHours(ProjectBooking projectBookingInstance){

        Project project = projectBookingInstance.project
        SubProject subProject = projectBookingInstance.subProject

        Double duration = (projectBookingInstance.duration/60)
        duration = duration.round(2)

        project.actualHours += duration
        subProject.actualHours += duration

        project.save(flush:true)
        subProject.save(flush:true)
    }
Christian
  • 821
  • 1
  • 11
  • 26
  • possibly move that logic from controller to service and simplify it as much as possible in controller. Incidentally ProjectBooking.get(projectBookingInstance.id) what is projectBookingInstance is that an instance of ProjectBooking (what you are getting again) ? I mean it seems you are looping what you already have ? – V H Jun 21 '15 at 17:01
  • With this line I want to get the persisted version from this booking before the update. But now I see that I am directly getting the updated version. Is there a way to get the one before the update? – Christian Jun 21 '15 at 17:04
  • I would move it to service and wrap @transactional around this call and you may need to then look at acid. https://github.com/vahidhedayati/documentation/blob/master/grails/acid.md – V H Jun 21 '15 at 17:12
  • Ok, thanks I will try moving the code into a service. But this wont solve the problem receiving with get the instance I already got in the update? Is there an easy way to get the "old" instance? For simple properties I can just call `.getPersistedValue("propertyname")` – Christian Jun 21 '15 at 17:18
  • http://stackoverflow.com/questions/19313629/getting-object-field-previous-value-hibernate-jpa I would look at .withTransaction{ around your new get... as a hack to see if it proceeds on – V H Jun 21 '15 at 17:21
  • Ah ok, I can try and save the previous instance in a transient attribute which I can set in a `beforeUpdate` interceptor. I just thought there could be anything "easier". I'll try both options tomorrow and then update my post accordingly – Christian Jun 21 '15 at 17:55
  • I was looking at something else but it may be related to this - since you can possibly use this technique to get what you require. http://stackoverflow.com/questions/18794636/grails-domain-dirtypropertynames-for-child-object?answertab=active#tab-top – V H Jul 01 '15 at 11:13

0 Answers0