2017-08-14 12 views
0

Nous avons récemment mis à jour de Grails 2.2.4 à 3.2.2. Depuis lors, nous avons eu des problèmes en essayant de conserver un objet nouvellement créé avec une clé composite.Grails 3 - objet de domaine avec clé composite ne pas toujours enregistrer

Disons que nous avons un objet de domaine appelé SomeField.

class SomeField { 

    static belongsTo = [parentClass : SomeParentClass] 

    static hasMany = [joinedFields : JoinedField] 

    joinedFields fetch:'join', cascade:'all-delete-orphan' 

} 

Il existe un autre objet de domaine appelé JoinedField qui appartient à l'un de ses deux membres SomeField. Il utilise les deux champs pour créer sa clé composite.

class JoinedField { 

    SomeField field1 
    SomeField field2 

    static belongsTo = [field1: SomeField] 

    static mapping = { 
     id composite: ['field1', 'field2'] 

     columns { 
      field1 column:'F1_ID' 
      field2 column:'F2_ID' 
     } 

     version false 
    } 

    static contraints = { 
     field1(nullable:false) 
     field2(nullable:false) 
    } 

    def getPk = { 
     ['field1':field1.id, 'field2':field2.id] 
    } 
} 

Champ2 existe toujours déjà dans la base de données et se leva les yeux de là quand ajouter l'objet JoinedField.

Lorsque le parent de champ1 est tout nouveau et que nous l'enregistrons, field1 est enregistré et l'objet JoinedField est conservé avec les deux clés comme prévu. Toutefois, lorsque le parent de field1 a déjà été enregistré, et que l'objet JoinedField est ajouté à un objet field1 existant ou à un nouvel objet field1 et enregistré, l'objet JoinedField n'est pas conservé.

Exemple:

someParent.addToFields(aRealField1) 

def jf = new JoinedField() 
aRealField1.addToJoinedFields(jf) 
jf.field2 = SomeField.findById(1234) 

someParent.save() 

Donc - si aRealField1 appartient à un parent qui n'a pas encore enregistré, puis 'aRealField1' et '' sont jf persistent lorsque le parent de aRealField1 est enregistré. Si le parent de field1 existe déjà, alors 'jf' n'est pas sauvegardé quand le parent de aRealField1 est sauvegardé, même si aRealField1 est bien sauvegardé.

Je suppose que GORM ne reconnaît pas cet objet comme étant sale et nécessitant une persistance car il est créé à partir de deux objets existants, même s'il s'agit d'un nouvel objet lui-même constitué de ces deux objets existants. Mais je ne vois pas de moyen de forcer cette sauvegarde en cascade à se produire dans ce cas. Tout fonctionnait avec Grails 2.2.4.

Mise à jour:

Il semble qu'il y ait un problème de transaction au cœur de cela. Nous avons un contrôleur pour SomeParentClass où la demande est reçue pour enregistrer l'objet. Cela appelle à son tour une classe de service transactionnelle à l'intérieur d'une fermeture 'withTransaction' pour nous permettre d'annuler la transaction si des erreurs surviennent. Le service effectue de nombreuses sauvegardes et nous souhaitons conserver la possibilité d'annuler l'ensemble du jeu en cas d'erreur.

Si nous supprimons l'annotation @Transactional sur le service et la fermeture withTransaction dans le contrôleur, la classe JoinedField ci-dessus enregistre très bien. Cependant, il nous manque la restauration de l'ensemble complet des modifications lorsqu'une erreur se produit.

Nous avons supprimé withTransaction dans le contrôleur et pouvons gérer l'annulation dans le service lorsqu'il est toujours annoté comme transactionnel, mais l'objet JoinedField ne peut toujours pas persister comme décrit.

Exemple: Code avec rollback seulement en service est plus propre:

import grails.transaction.Transactional 

@Transactional 
class BuildObjectService { 

    def buildObject(def json) { 
     try { 
      // build the object from json representation 
     } 
     catch(Exception e) { 
      transactionStatus.setRollbackOnly() 
      throw e 
     } 
    } 
} 

Toutes les idées sur pourquoi cela ne persiste lorsque dans un service transactionnel, mais fait très bien quand cette annotation est supprimée?

Répondre

0

Résolution de ce problème en mettant à niveau org.grails: grails-datastore-gorm *, org.grails: grails-datastore-core et org.grails.plugins: hibernate5 à la dernière version 6.1.6.RELEASE.Ceci remplace les versions 6.0.3 qu'utilisait org.grails: grails-depenedencies.