2010-01-15 5 views
11

Cette question est en deux parties, la première partie traite de la suppression d'une liste et la seconde partie concerne l'affectation d'un propriétaire à un objet.Comment effacer et remplacer une collection dans une relation un-à-plusieurs dans Grails/Groovy

J'ai une relation un-à-plusieurs entre deux objets de domaine dans mon modèle dans Grails. La relation ressemble à ceci ...

class Person { 

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

class Location { 

    static belongsTo = Person 

} 

Dans mon application la liste locations sur Person obtient complètement rafraîchi et remplacé par une nouvelle liste sur une action de l'utilisateur. De plus, j'obtiens la liste des objets Location indépendants du Person associé. Je décide à quelle personne de les appliquer en récupérant l'utilisateur actuellement connecté, que j'appelle activePerson et est bien pour mes fins. Ce que je veux faire est de supprimer tous les emplacements existants sur activePerson et d'insérer tous les nouveaux, en les associant au activePerson comme je vais. J'ai un tas de propriétés sur Person que je ne veux pas persister à ce stade, donc je veux éviter d'enregistrer l'objet parent entier juste parce que les emplacements des enfants ont changé.

J'ai pensé à parcourir la liste activePerson.locations et de les supprimer un par un et de me fier à GORM/Hibernate pour regrouper les requêtes et les rincer à la fin. Cela semble être une force brute, bien que cela puisse fonctionner. Je m'attendais à ce qu'il y ait une méthode clearLocations ou quelque chose de similaire, mais je ne peux pas en trouver un.

Si je remplace simplement le activePerson.locations par une nouvelle liste et appelez activePerson.save(flush:true), GORM va-t-il gérer la suppression des lignes existantes?

Deuxièmement, je veux mettre les nouveaux objets Location sur activePerson. Encore une fois, je pourrais remplir le activePerson.locations et enregistrer le tout, mais je voudrais éviter cela si je peux. Je peux les enregistrer individuellement, mais comment puis-je définir belongsTo sur chaque objet Location comme je vais?

Pour résumer:

  1. Comment effacer une liste à la fin d'un grand nombre d'un à plusieurs collection?
  2. Comment associer des objets indépendants à un objet parent et les conserver individuellement?

Merci

Répondre

8

Pour # 1, vous pouvez effacer la collection (il est un ensemble par défaut):

activePerson.locations.clear() 

Pour # 2 utilisation addToLocations:

activePerson.addToLocations(location) 

et quand vous enregistrer la personne l'emplacement < -> relation personne sera mis à jour.

+0

@Burt, merci (encore) pour votre réponse, je vous dois une bière. Cela implique cependant que je dois persister l'objet Person, que j'essayais d'éviter. Y a-t-il une alternative raisonnable ou devrais-je simplement vivre avec la mise à jour d'un disque qui n'a pas vraiment changé? – Simon

+0

En plus de la réponse de Burt, vous devrez peut-être implémenter equals et hashcode sur l'objet de collection, et spécifier cascade: "all-delete-orphelin" sur le mappage de la collection. –

+2

'activePerson.locations.clear()' sur la collection ne fonctionnera pas. Essayez: 'activePerson.locations.collect(). Each {item.removeFromLocations (it)}' – Athlan

8

Effacement approche Collection n'a pas fonctionné pour moi:

activePerson.locations.clear() 

Juste essayer itérer sur la collection avec évitant ConcurrentModificationException en appelant collect():

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

Et après que sauver l'entité à exécuter l'instruction SQL :

activePerson.save flush:true 

Lien vers l'article pour en savoir plus: http://spring.io/blog/2010/07/02/gorm-gotchas-part-2/

+0

cela n'a pas fonctionné pour moi jusqu'à ce que je spécifie orphanRemoval = true sur l'entité @OneToMany (..., orphanRemoval = true) – Mahakala

+2

Est-ce que 'item' ne devrait pas être 'activePerson'? Alors, nous pouvons appeler removeFromLocations (it)? –

6

Bien que ce soit une question plus, je suis tombé dans une situation très similaire dans lequel je voulais mettre à jour un ensemble d'enregistrements d'enfants. Voici comment j'ai choisi de le résoudre. Pour simplifier, j'utiliserai les mêmes noms d'objet/relation que le demandeur de la question.

  1. Dans le bloc mapping du domaine parent, ajoutez:

    static mapping = { 
        locations(cascade: "all-delete-orphan") 
    } 
    
  2. Dans le domaine de l'enfance, ajoutez l'annotation @EqualsAndHashCode (juste au cas où il y a une autre rôde, je fais référence à groovy.transform.EqualsAndHashCode).

  3. Ajoutez tous les éléments enfants au domaine parent à l'aide des méthodes Grails addTo (par exemple, addToLocations), puis enregistrez le domaine parent.

Bien que cette approche ne nécessite l'enregistrement du domaine parent (que le demandeur ne voulait pas le faire), il semble que c'est l'approche la plus appropriée compte tenu de la claire définition belongsTo dans le modèle. Je voudrais donc répondre aux questions de Asker numérotées comme ceci:

  1. plutôt que de le faire manuellement, laissez Grails/Hibernate effacer les enregistrements en spécifiant le comportement en cascade all-delete-oprhan sur la relation. Ne tentez pas d'enregistrer directement les enregistrements enfants, mais enregistrez l'objet parent pour qu'il corresponde à ce que Grails semble attendre.

Questions connexes