2011-01-26 12 views
5

tengo la siguiente excepción al guardar una instancia de viaje en Grails:Griales Gorm: Objeto referencia a una instancia transitoria no salvo

2011-01-26 22: 37: 42,801 [http-8090-5] ERROR errors.GrailsExceptionResolver - objeto hace referencia a una instancia transitoria no salva - guardar la instancia transitoria antes de lavar: Rower org.hibernate.TransientObjectException: hace referencia a un objeto no guardado transitoria ejemplo - guardar la instancia transitoria antes de lavar: Rower

El concepto es simple: para una excursión en barco necesita algunos remeros, un timonel (es también un remero) y un barco:

viaje se parece a (abreviado):

class Trip { 
    Boat boat; 
    Rower coxwain; 

    static belongsTo = [Rower,Boat] 
    static hasMany = [rowers:Rower] 
} 

y Remo (acortados)

class Rower { 
    String firstname; 
    String name; 
    Rower reference; 

    static hasMany = [trips:Trip]; 
    static mappedBy = [trips:"rowers"] 
} 

el viaje, entonces se guarda en el controlador como:

def save = { 
     def trip = new Trip(params) 

     // adding Rowers to Trip 
     if (params.rower instanceof String) { 
      def r = Rower.get(params?.rower) 

      if (r != null) { 
       trip.addToRowers(r) 
      } 
     } else { 
      params?.rower?.each{ 
       rowerid -> 
       def r = Rower.get(rowerid) 
       log.info("rowerid (asList): " + rowerid) 
       if (r != null) { 
        trip.addToRowers(r) 
       } 
      } 
     } 

     // saving the new Trip -> EXCEPTION IN NEXT LINE 
     if(!trip.hasErrors() && trip.save(flush:true)) { 
      // ... 
     } 
     // ... 
} 

Creo que he corregido las relaciones entre los dominios. El Rower no se cambia mientras se agrega al viaje. ¿Por qué Grails quiere que se guarde? ¿Por qué es una instancia transitoria?

+0

¿Ocurre en ambos bloques de regulación (es decir, el si y el otro)? –

+0

¿Recibió algún mensaje de registro? –

Respuesta

0

Creo que debe guardar el viaje antes de agregar el móvil al viaje. Tampoco tiene sentido comprobar si el viaje tiene errores antes de validarlo o guardarlo.

Prueba esto:

if(trip.validate() && trip.save(flush:true)) { 
    if (r != null) { 
     trip.addToRowers(r) 
    } 
} 
0

Al principio pensé que tenía que ver con cascada y ahorra belongsTo, como se describe en el apartado 5.2.1.3 y The Grails ReferenceGorm Gotchas part 2. Sin embargo, dado que los Rowers ya están en DB, creo que debería funcionar. El modelo de dominio es complicado para mí, lo que necesita hacer es simplificarlo y ejecutar algunas pruebas usando la consola de Grails (ejecute la consola de Grails en su directorio de proyecto). Primero crea un múltiplo básico entre Trip y Rower y haz que ejecute el código deseado. Luego agregue las otras partes bit por bit, como la referencia de Rower a sí misma. No estoy seguro de que la parte mappedBy sea necesaria.

1

El problema era de alguna manera diferente. Está en aquí:

def trip = new Trip(params) 

que hace referencia a un timonel (de clase Rower), que no se establece (id = -1 se devuelve). Esto construye un nuevo Rower en lugar de un valor 'nulo'. Y esta es la 'instancia transitoria no salvada'. Si primero verifico si hay una instancia válida, entonces funciona :-)

¡Gracias por la ayuda!

6

Desafortunadamente, este es un problema con la forma en que GORM maneja las cosas, o más específicamente la forma en que espera que se ocupe de los transitorios. Si no persiste las clases contenidas en la base de datos primero (Rowers en este caso), obtendrá esta excepción cada vez.

Con GORM tiene que guardar y adjuntar en forma ascendente o cuando se cierra la conexión para la siguiente instancia, obtendrá la excepción de instancia transitoria. La instancia es 'transitoria' porque es solo una referencia en memoria. Para persistir al padre, GORM necesita vincular el padre con el hijo en la base de datos. Sin que se persista al niño, no tiene forma de hacerlo, aquí es de donde proviene la excepción.

Ojalá hubiera mejores noticias. No es difícil, pero se vuelve molesto con jerarquías complejas.

1

Sólo una nota rápida para cualquiera que se relacione con los parámetros singulares o múltiples con el mismo nombre, utilizando el ayudante params.list("parameterName") siempre se puede devolver una lista

... 

    // adding Rowers to Trip 
    if (params.rower instanceof String) { 
     def r = Rower.get(params?.rower) 

     if (r != null) { 
      trip.addToRowers(r) 
     } 
    } else { 
     params?.rower?.each{ 
      rowerid -> 
      def r = Rower.get(rowerid) 
      log.info("rowerid (asList): " + rowerid) 
      if (r != null) { 
       trip.addToRowers(r) 
      } 
     } 
    } 

    ... 

podría llegar a ser un poco más groovy

... 

    // adding Rowers to Trip 
    for(rower in params.list("rower") { 
     def r = Rower.get(rower) 
     if(r) trip.addToRowers(r) 
    } 

    ... 

puede encontrarlo escondido bajo 6.1.12 Simple Type Converters

Cuestiones relacionadas