2010-08-24 2 views
2

Lorsque je modifie un objet de domaine, plutôt que de mettre à jour l'enregistrement de la base de données, je souhaite archiver l'ancien enregistrement d'enregistrement et en créer un nouveau. Je voudrais forcer GORM à le faire automatiquement.Les classes de domaine peuvent-elles être configurées pour insérer un nouvel enregistrement au lieu de la mettre à jour lors de l'enregistrement?

Par exemple, si j'avais cette classe de domaine:

class User { 
    String username 
    String email 
    Boolean active 
} 

je voudrais

user.email = email 
user.save() 

pour définir le drapeau actif sur l'utilisateur de faux, en gardant une trace de l'ancien email. Un nouvel enregistrement avec la nouvelle adresse e-mail et active = true sera inséré.

Est-ce un modèle courant? Est-ce facile à faire dans la classe du domaine pour que cela se fasse de manière transparente?

Répondre

2

Vous pouvez utiliser l'événement GORM beforeUpdate en classe de domaine utilisateur (voir la documentation here et here) avec quelque chose comme ce qui suit devrait fonctionner (non testé):

def beforeUpdate() { 
    if (isDirty('email') { //enters only if email was changed. Works only with Grails 1.3.x 
    User.withNewSession { 
    //Create the new entry 
    new User(username:username, email:email).save() 
    //Update the old entry with the old email value 
    email = getPersistentValue('email') 
    } 
    } 
} 
+0

Intéressant, je n'y ai pas pensé. Mais comment obtenez-vous le nouvel utilisateur inséré (pour remplacer votre ancienne instance)? –

+0

Si je crée le nouvel utilisateur dans une nouvelle session, ce sera dans une autre transaction, n'est-ce pas? Idéalement, je voudrais qu'il revienne avec le reste de la transaction si quelque chose échoue. – ataylor

+0

@ataylor oui c'est une autre transaction. Vérifiez simplement la valeur de retour de save() et propage l'erreur à l'autre transaction pour la reculer @Pascal La seule façon dont j'ai maintenant en tête est: User.findByEmail (new_email), ou de stocker le nouvel ID utilisateur dans une portée comme session ou flash – fabien7474

2

Une option que je peux penser serait d'implémenter un soft delete, puis persister un nouvel utilisateur. Je me rends compte que ce n'est pas exactement ce que vous demandez, mais je ne sais pas comment le faire avec une seule sauvegarde. IMO pas idéal.

Une autre (probablement meilleure) approche serait d'utiliser Hibernate Envers pour "version" l'entité User et conserver un historique des modifications. Je ne connais pas le statut exact d'Envers avec Grails mais il semble qu'il y ait un plugin pour cela. Voir aussi [grails-user] GORM & Envers/Audit History Tables.

+0

Ceci est aussi une bonne solution globale. Avez-vous déjà essayé Envers avec Grails? – fabien7474

+0

@ fabien7474: Non, jamais. Honnêtement, je ne sais pas quel est le statut actuel de Envers avec Grails (je ne fais pas vraiment de Grails). –

Questions connexes