2010-01-15 8 views
11

? Esta pregunta consta de dos partes, la primera parte se trata de borrar una lista y la segunda parte se trata de asignar un propietario a un objeto.¿Cómo elimino y reemplazo una colección en una relación de uno a muchos en Grails/Groovy

Tengo una relación uno a muchos entre dos objetos de dominio en mi modelo en Grails. La relación se ve así ...

class Person { 

    static hasMany = [authorities: Role, locations: Location] 
} 

class Location { 

    static belongsTo = Person 

} 

En mi aplicación en la lista locationsPerson queda completamente renovado y reemplazado con una nueva lista en una acción del usuario. Además, obtengo la lista de los objetos Location independientes del Person asociado. Resuelvo a qué persona aplicarlos recuperando el usuario actualmente conectado, al que llamo activePerson y está bien para mis propósitos.

Lo que quiero hacer es eliminar todas las ubicaciones existentes en activePerson e insertar todas las nuevas, asociándolas con el activePerson sobre la marcha. Tengo un montón de propiedades en Person que no quiero que persistan en este momento, así que quiero evitar guardar todo el objeto principal solo porque las ubicaciones de los elementos han cambiado.

Pensé en iterar a través de la lista activePerson.locations y eliminarlos uno por uno y confiar en GORM/Hibernate para agrupar las consultas en conjunto y vaciar al final. Esto parece una fuerza bruta, aunque podría funcionar. Esperaba que hubiera un método clearLocations o algo similar, pero no puedo encontrar uno.

Si solo reemplazo el activePerson.locations con una nueva lista y llame al activePerson.save(flush:true), ¿GORM manejará la eliminación de las filas existentes?

En segundo lugar, quiero poner los nuevos objetos Location en . Una vez más pude llenar el activePerson.locations y guardar todo, pero me gustaría evitar eso si puedo. Puedo guardarlos individualmente, pero ¿cómo configuro belongsTo en cada objeto Location mientras voy?

Así que para recapitular:

  1. ¿Cómo se borra una lista en la que muchos terminan de una colección de uno a muchos?
  2. ¿Cómo puedo asociar objetos independientes con un objeto primario y persistirlos individualmente?

Gracias

Respuesta

8

Para # 1 puede borrar la colección (que es un conjunto por defecto):

activePerson.locations.clear() 

Para # 2 addToLocations uso:

activePerson.addToLocations(location) 

y cuando salvar a la persona la ubicación < -> relación persona se actualizará.

+0

@Burt, gracias (de nuevo) por su respuesta, le debo una cerveza. Sin embargo, esto implica que tengo que persistir en el objeto Persona, que estaba tratando de evitar. ¿Existe una alternativa sensata o debería simplemente vivir con la actualización de un registro que realmente no ha cambiado? – Simon

+0

Además de la respuesta de Burt, puede que necesite implementar equals y hashcode en el objeto de colección, y especifique cascade: "all-delete-huérfano" en la asignación de la colección. –

+2

'activePerson.locations.clear()' en la colección no funcionará. Pruebe: 'activePerson.locations.collect(). Each {item.removeFromLocations (it)}' – Athlan

8

Borrado Collection enfoque no funcionó para mí:

activePerson.locations.clear() 

Solo trata de iterar sobre la colección con evitar ConcurrentModificationException llamando collect():

activePerson.locations.collect().each { 
    item.removeFromLocations(it) 
} 

Y después de eso guardar la entidad para ejecutar SQL :

activePerson.save flush:true 

Enlace al artículo para leer más: http://spring.io/blog/2010/07/02/gorm-gotchas-part-2/

+0

que no funcionó para mí hasta que especifique orphanRemoval = true en la Entidad @OneToMany (..., orphanRemoval = true) – Mahakala

+2

¿No debería 'item' ser 'activePerson'? Entonces, ¿de esa manera podemos llamar removeFromLocations (it)? –

6

Si bien esto es una cuestión mayor, me encontré con una situación muy similar en el que quería actualizar un conjunto de registros secundarios. Así es como elegí resolverlo. Para simplificar, usaré los mismos nombres de objeto/relación que el asker de la pregunta.

  1. En el bloque del dominio principal mapping, añadir:

    static mapping = { 
        locations(cascade: "all-delete-orphan") 
    } 
    
  2. En el dominio secundario, añadir la anotación @EqualsAndHashCode (por si acaso hay otro al acecho, me refiero a groovy.transform.EqualsAndHashCode).

  3. Agregue todos los elementos secundarios al dominio principal utilizando los métodos Grails addTo (por ejemplo, addToLocations) y luego guarde el dominio principal.

Si bien este enfoque requiere guardar el dominio principal (que el autor de la pregunta no quería hacer), que parece que es el enfoque más apropiado dada la belongsTo definición clara en el modelo. Por lo tanto, me gustaría responder a las preguntas numeradas del autor de la pregunta de esta manera:

  1. En lugar de hacerlo manualmente, vamos Grails/Hibernate borrar los registros especificando el comportamiento all-delete-oprhan en cascada sobre la relación.

  2. No intente guardar los registros secundarios directamente, sino que guarde el objeto primario para que coincida con lo que Grails parece esperar.

Cuestiones relacionadas