grailsgrails-ormgrails-3.3

Grails 3.3: Is only the first save() persisted?


Is only the first save() on a domain object instance persisted?

Environment: Grails 3.3.5, GORM 6.1.9 I believe, PostgreSQL 9.5, JDK 1.8.0_171, Ubuntu 16.04.

My app creates Recital (domain object) instances based on input from a number of text files. This is a database load, so everything happens in one single controller call, calling a service method. One single transaction.

The service method parses the input streams looking for recitals. When it finds one it tries a findBy method (Recitals are numbered). If there is a Recital with the given number, it updates it from the input and does save(). Otherwise it creates a new instance from the input and does save(). failOnError everywhere for good measure. Recitals don't belongTo anything, no cascading issues.

The program logic has no way of telling if a modification is the last update on an instance. Thus there is a save() after every change. But this does not work. You can only save() once, it seems.

The net result found in the database is that only the first save() is persisted. When debugging the running program I can verify that instances are completely updated in memory.

If this is correct the documentation should say: The save method informs the persistence context that an instance should be saved or updated in its current state. Any and all modifications after this point (in the same transaction) will be ignored. The object will not be persisted immediately unless the flush argument is used...

P.S. The save() documentation explains "flush: true" as flushes the persistence context. This has little explanatory value to a newcomer. Some "flush" synonyms are: cleanse, erase, expunge, purge, sweep, wipe. A database person might get it as ROLLBACK rather than COMMIT. The explanation is, of course, Hibernate terminology. It's nice if the Grails doco is mostly self-contained. (Side issue in the same piece of documentation.)


Solution

  • Before too many people waste their time on this, here is some new insight.

    It so happens that the Recital domain has an embedded component. The updates in my app affect only members of the embedded component.

    I have verified that for three particular updates of one and the same instance the members are updated correctly in memory. However, after each of the three updates recital.isDirty() returns false, likewise recital.isDirty('body') where body is the embedded component.

    My conclusion is that updating an embedded component does not necessarily set the dirty flag on an instance. So it is not saved. Forget the theory proposed in the original question. There seems to be a Grails/GORM bug.

    My workaround for now is to replace updates by executeUpdate. A kludge, but I have spent too much time on this and must get on.

    EDIT: Not a bug. GORM now requires embedded classes to be annotated with @DirtyCheck for dirty checking to happen. Case closed.