2017-08-14 4 views
0

Wir haben vor kurzem von Grails 2.2.4 auf 3.2.2 aktualisiert. Seitdem hatten wir Probleme, wenn wir versuchten, ein neu erstelltes Objekt mit einem zusammengesetzten Schlüssel zu erhalten.Grails 3 - Domain-Objekt mit Composite-Key nicht immer speichern

Nehmen wir an, wir haben ein Domänenobjekt namens SomeField.

Es gibt ein anderes Domänenobjekt namens JoinedField, das zu einem seiner beiden SomeField-Mitglieder gehört. Es verwendet beide Felder, um seinen zusammengesetzten Schlüssel zu erstellen.

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] 
    } 
} 

Field2 existiert immer schon in der Datenbank und wird von dort aus sah auf, als es das JoinedField Objekt hinzufügen.

Wenn das Elternelement von Field1 neu ist und wir es speichern, wird field1 gespeichert und das JoinedField-Objekt wird wie erwartet mit den beiden Schlüsseln beibehalten. Wenn das Elternelement von Feld1 jedoch bereits gespeichert wurde und das JoinedField-Objekt einem vorhandenen field1-Objekt oder einem neuen field1-Objekt hinzugefügt und gespeichert wurde, wird das JoinedField-Objekt nicht beibehalten.

Beispiel:

someParent.addToFields(aRealField1) 

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

someParent.save() 

Also - wenn aRealField1 gehört zu einem Elternteil noch nicht gespeichert, dann ‚aRealField1‘ und ‚‘ jf beharrte, wenn aRealField1 der Eltern gespeichert wird. Wenn das Elternelement von field1 bereits vorhanden ist, wird 'jf' nicht gespeichert, wenn das Elternelement von aRealField1 gespeichert wird, obwohl aRealField1 ordnungsgemäß gespeichert wird.

Ich nehme an, GORM erkennt dieses Objekt nicht als schmutzig und benötigt Persistenz, weil es aus zwei vorhandenen Objekten erstellt wird, obwohl es ein neues Objekt selbst ist, das aus diesen beiden vorhandenen Objekten besteht. Aber ich sehe keine Möglichkeit, diese Kaskadenspeicherung in diesem Fall zu erzwingen. Es hat alles mit Grails 2.2.4 gearbeitet.

Update:

Es scheint, dass es eine Transaktion Ausgabe im Herzen dieser ist. Wir haben einen Controller für SomeParentClass, in dem die Anforderung zum Speichern des Objekts empfangen wird. Dies wiederum ruft eine transaktionale Serviceklasse innerhalb eines 'withTransaction'-Abschlusses auf, um es uns zu ermöglichen, die Transaktion rückgängig zu machen, wenn Fehler auftreten. Der Dienst führt zahlreiche Speichervorgänge aus, und wir möchten die Möglichkeit behalten, bei Fehlern den gesamten Satz zurückzusetzen.

Wenn wir die @Transactional-Annotation für den Service und die withTransaction-Closure im Controller entfernen, wird die JoinedField-Klasse oben problemlos gespeichert. Es fehlt uns dann jedoch das Zurücksetzen des vollständigen Satzes von Änderungen, wenn ein Fehler auftritt.

Wir haben die withTransaction im Controller entfernt und können das Rollback im Service behandeln, wenn es noch als Transactional annotiert ist, das JoinedField-Objekt jedoch weiterhin nicht wie beschrieben bestehen bleibt.

Beispiel: Code mit Rollback nur in Betrieb ist saubersten:

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 
     } 
    } 
} 

Alle Ideen, warum dies nicht gelingt, wenn sie innerhalb einer Transaktionsdienst zu bestehen aber tut gut, wenn die Anmerkung entfernt wird?

Antwort

0

Behebung dieses Problems durch Upgrade von org.grails: grails-datastore-gorm *, org.grails: grails-datastore-core und org.grails.plugins: hibernate5 auf die neueste Version 6.1.6.RELEASE.

Dies ersetzt die 6.0.3-Versionen, die die org.grails: grails-dependencies gezogen hat.