Search code examples
grailsgrails-orm

grails gorm cascading save best practice


I have some working code but I'm a little fuzzy on GORM and cascading saves. Here is my object model:

class Profile {
   PhotoAlbum photoAlbum

   static constraints = {
       photoAlbum(nullable:true)
   }
}

class PhotoAlbum {
   static hasMany = [photos:Photo]
   static belongsTo = [profile:Profile]
}

class Photo {
    static belongsTo = PhotoAlbum
}

And here is my working code to save a new photo object:

Photo photo = new Photo()

if (!profile.photoAlbum) { profile.photoAlbum = new PhotoAlbum(profile:profile) }

profile.photoAlbum.addToPhotos(photo)


if (!photo.save()) {
   def json = [
           status:'fail',
           message:messageSource.getMessage('label.photo.validate.failed.message', [photo.errorStrings].toArray(), LocaleContextHolder.locale)
   ]
   return json
}
if (!profile.photoAlbum.save()) {
   def json = [
           status:'fail',
           message:messageSource.getMessage('label.photo.validate.failed.message', [profile.photoAlbum.errorStrings].toArray(), LocaleContextHolder.locale)
   ]
   return json
}

if (!profile.save()) {
   def json = [
           status:'fail',
           message:messageSource.getMessage('label.photo.validate.failed.message', [profile.errorStrings].toArray(), LocaleContextHolder.locale)
   ]
   return json
}
else {
   def json = [
           status:'success',
           message:messageSource.getMessage('label.photo.insert.success.message', null, LocaleContextHolder.locale)
   ]
   return json
}

It seems like a lot of code and error checking to save a new photo object. When I look at grails examples on websites and in books, I don't see a lot of error checking. In my case if a photo cannot be saved, the service has to return a json error string to the client. I have read the GORM Gotchas 2 post, but I'm still not clear on cascading saves.

I did find that if I don't call photo.save() and profile.photoAlbum.save() and just call profile.save() I get the transient exception. So I added in photo.save() and profile.photoAlbum.save() to get everything working.


Solution

  • As @Cregg mentioned you should move all your logic to service, in order to handle all calls to DB in one transaction. To not get the transient exception try to use following:

    profile.save(flush: true, failOnError:true)
    

    You should create ErrorController to handle all your exceptions. See example.