Grails saving domain object with invalid state

View: New views
9 Messages — Rating Filter:   Alert me  

Grails saving domain object with invalid state

by ndijkstra :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello,

i have a scenario in a Grails 1.1 application where a controller populates a domain object and passes it to a service for validation and saving (some business logic is also included in the service method being called). The service has transactional=true and i found that the object is saved when passed as a parameter in the call from the controller to the service method even calling domainObj.discard() inside the service method, doesn't discard (because the object is saved already but not necesarilly valid tough). Is this supposed to be that way? Where is the transaction created? In the controller or in the service?

I also found that changing transactional=false makes the service work as expected.

Here's a step-by-step if the former explanation was not clear enough (most probably due to my poor english writing):
1.- Controller finds domain object by params.id
2.- Controller populates domain object with data from params map
3.- Controller calls service.saveObj(domainObj)
3.1.- Domain object is saved (even if it's not valid)
3.2.- Service method is called
3.3.- A call to domainObj.discard() doesn't work!!

Any help or clue will be appreciated.

Regards,
Nicolás

Re: Grails saving domain object with invalid state

by Peter Ledbrook :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

> Here's a step-by-step if the former explanation was not clear enough (most
> probably due to my poor english writing):
> 1.- Controller finds domain object by params.id
> 2.- Controller populates domain object with data from params map
> 3.- Controller calls service.saveObj(domainObj)
> 3.1.- Domain object is saved (even if it's not valid)
> 3.2.- Service method is called

A transactional service method will automatically flush the Hibernate
session when it completes. Do you call discard() from within the
service method, or afterwards in the controller? If the latter, it's
too late because the transaction flushed the session.

Try moving the call to discard() into the service method.

Cheers,

Peter

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Grails saving domain object with invalid state

by ndijkstra :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Peter,

discard() is being called from within the service method. I debugged the domain object and noticed it is saved to de database with the call to the service method.

Nicolás

On Tue, Oct 27, 2009 at 3:52 AM, Peter Ledbrook <peter@...> wrote:
> Here's a step-by-step if the former explanation was not clear enough (most
> probably due to my poor english writing):
> 1.- Controller finds domain object by params.id
> 2.- Controller populates domain object with data from params map
> 3.- Controller calls service.saveObj(domainObj)
> 3.1.- Domain object is saved (even if it's not valid)
> 3.2.- Service method is called

A transactional service method will automatically flush the Hibernate
session when it completes. Do you call discard() from within the
service method, or afterwards in the controller? If the latter, it's
too late because the transaction flushed the session.

Try moving the call to discard() into the service method.

Cheers,

Peter

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email




Re: Grails saving domain object with invalid state

by Peter Ledbrook :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

> discard() is being called from within the service method. I debugged the
> domain object and noticed it is saved to de database with the call to the
> service method.

Could you post the code that's in your service method?

Thanks,

Peter

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Grails saving domain object with invalid state

by ndijkstra :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Here goes the service method code.

class AssignmentTaskService {
    def projectService

    boolean transactional = false

    boolean saveTask(AssignmentTask task) {
        if (task.absence && !task.absence.isShiftEnabled) {
            task.shift1Start = null
            task.shift1End = null
            task.shift2Start = null
            task.shift2End = null
            task.tripTime = 0F
        }

        if (task.validate()) {
            if (task.absence?.endsAssignment) {
                projectService.endAssignment(task.assignment, task.date, task.absence)
            }
            task.save()
            return true
        } else {
            task.discard()
            return false
        }
    }
}


On Tue, Oct 27, 2009 at 10:05 AM, Peter Ledbrook <peter@...> wrote:
> discard() is being called from within the service method. I debugged the
> domain object and noticed it is saved to de database with the call to the
> service method.

Could you post the code that's in your service method?

Thanks,

Peter

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email




Re: Grails saving domain object with invalid state

by ndijkstra :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Peter, any clues about this strange behaviour?

The only workaround i found was changing the service's transactional flag to false

Regards,
Nicolás

2009/10/27 Nicolás Dijkstra <nicolas.dijkstra@...>
Here goes the service method code.

class AssignmentTaskService {
    def projectService

    boolean transactional = false

    boolean saveTask(AssignmentTask task) {
        if (task.absence && !task.absence.isShiftEnabled) {
            task.shift1Start = null
            task.shift1End = null
            task.shift2Start = null
            task.shift2End = null
            task.tripTime = 0F
        }

        if (task.validate()) {
            if (task.absence?.endsAssignment) {
                projectService.endAssignment(task.assignment, task.date, task.absence)
            }
            task.save()
            return true
        } else {
            task.discard()
            return false

        }
    }
}


On Tue, Oct 27, 2009 at 10:05 AM, Peter Ledbrook <peter@...> wrote:
> discard() is being called from within the service method. I debugged the
> domain object and noticed it is saved to de database with the call to the
> service method.

Could you post the code that's in your service method?

Thanks,

Peter

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email





Re: Grails saving domain object with invalid state

by Peter Ledbrook :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

> Hi Peter, any clues about this strange behaviour?
> The only workaround i found was changing the service's transactional flag to
> false

Not sure. I'm hoping that Burt comes along with his Hibernate/Spring
fu to explain why the session may appear to be flushed at the start of
the transaction. You're definitely not calling save() from the
controller? You're just binding the "params" map to an existing
AssignmentTask?

Peter

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Grails saving domain object with invalid state

by Graeme Rocher-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Fri, Nov 6, 2009 at 7:01 AM, Peter Ledbrook <peter@...> wrote:
>> Hi Peter, any clues about this strange behaviour?
>> The only workaround i found was changing the service's transactional flag to
>> false
>
> Not sure. I'm hoping that Burt comes along with his Hibernate/Spring
> fu to explain why the session may appear to be flushed at the start of
> the transaction. You're definitely not calling save() from the
> controller? You're just binding the "params" map to an existing
> AssignmentTask?

I believe this is the Grails 1.1 bug where we were proxying the
getMetaClass() method. So

getMetaClass().invokeMethod("transactionalMethod", null)

Resulted in one transaction for getMetaClass (and associated flush)
and a second for the invocation of "transactionalMethod"

Cheers

>
> Peter
>
> ---------------------------------------------------------------------
> To unsubscribe from this list, please visit:
>
>    http://xircles.codehaus.org/manage_email
>
>
>



--
Graeme Rocher
Head of Grails Development
SpringSource - A Division of VMware
http://www.springsource.com

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Grails saving domain object with invalid state

by Burt Beckwith :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Right, so the workaround I used was to pass the updated request parameters (or the whole params if there are a lot) to the service method and have it make all of the changes and then save. That way the flush that was triggered by the getMetaClass() call didnt' have any effect:

class AssignmentTaskController {

   def assignmentTaskService

   def update = {
      def task = AssignmentTask.get(params.id)
      assignmentTaskService.saveTask task, params
      ...
   }
}

class AssignmentTaskService {
   def projectService

   boolean transactional = true

   boolean saveTask(AssignmentTask task, params) {
      task.params = params
      if (task.absence && !task.absence.isShiftEnabled) {
      ...
      }
   }
}

Burt

> On Fri, Nov 6, 2009 at 7:01 AM, Peter Ledbrook <peter@...> wrote:
> >> Hi Peter, any clues about this strange behaviour?
> >> The only workaround i found was changing the service's transactional flag to
> >> false
> >
> > Not sure. I'm hoping that Burt comes along with his Hibernate/Spring
> > fu to explain why the session may appear to be flushed at the start of
> > the transaction. You're definitely not calling save() from the
> > controller? You're just binding the "params" map to an existing
> > AssignmentTask?
>
> I believe this is the Grails 1.1 bug where we were proxying the
> getMetaClass() method. So
>
> getMetaClass().invokeMethod("transactionalMethod", null)
>
> Resulted in one transaction for getMetaClass (and associated flush)
> and a second for the invocation of "transactionalMethod"
>
> Cheers
> >
> > Peter
> >
> > ---------------------------------------------------------------------
> > To unsubscribe from this list, please visit:
> >
> >    http://xircles.codehaus.org/manage_email
> >
> >
> >
>
>
>
>


signature.asc (204 bytes) Download Attachment