apache / apache/grails-core

Domain Merge does not flush dirty fields to datastore

Open
#14,354 2 comments 0 reactions 0 assignees View on GitHub
relates-to: grails-data-hibernate5
Dominant language
Groovy
Stars
2.9k
Forks
975
Avg merge
1d 22h
Merged PRs (30d)
92

Description

I'm trying to manage updates to a domain object through different controller actions with the object stored in the session. At the end of the editing I'm doing a merge to push the changed fields of the object to the datastore. The merge completes without error but the changes are not sent to the database.

I've reproduced with a simple project -
[grailsMergeBug-bug-report-01112022.zip](https://github.com/grails/gorm-hibernate5/files/9909773/grailsMergeBug-bug-report-01112022.zip). Go to http://localhost:8080/data to reproduce.

The domain object looks like this:
```
package grailsmergebug

import groovy.transform.ToString

@ToString(includePackage = false, includes = ['name', 'number'], includeNames = true)
class Data {

String name
Integer number

static constraints = {}
}
```
Changes to the `name` or `number` fields do not get merge saved.
I've simulated the editing, storing in session and merge in a controller:
```
...
@Transactional
def index() {

Data.deleteAll([flush: true], Data.list())
Data data = new Data(name: "data1", number: 1)
data.save()

redirect(action: 'putInSession')
}

def putInSession() {

Data data = Data.list().first()
data.name = "dirtied"
data.number += 1

logDirtyStatus(data, "putInSession")
session.data = data

redirect(action: 'tryMerge')
}

@Transactional
def tryMerge() {

Data data = session.data
logDirtyStatus(data, "tryMerge")

log.debug "doing merge..."
def mergeRet = data.merge(failOnError: true, flush: true)
log.debug "merge return data: $data"
session.data = null

redirect(action: 'checkSaved')
}

def checkSaved() {

Data data = Data.list().first()
log.debug "checkSaved data: $data"

render "$data -- ${data.name == 'dirtied' ? 'changed OK' : 'did not merge the changes'}"
}

private def logDirtyStatus(Data data, String prefix)
{
log.debug "[$prefix] val: $data.name | hasChanged: ${data.hasChanged()} | hasChanged(field): ${data.hasChanged("name")} | " +
"list dirty: ${data.listDirtyPropertyNames()} | get dirty: ${data.getDirtyPropertyNames()} | " +
"dirty: ${data.dirty} | dirty(field): ${data.isDirty("name")}"
}
...
```

Going to checkSaved action in a browser shows that the object has not been updated.

Versions:
```
grailsVersion=5.2.3
grailsGradlePluginVersion=5.2.3
groovyVersion=3.0.11
gorm.version=7.3.2
```

Contributor guide

Open the contributing guide

Research direction

Start with the attached grailsMergeBug-bug-report-01112022.zip and reproduce the behavior by visiting /data. Read the controller actions putInSession, tryMerge, and checkSaved, then trace the merge call and its flush behavior. Done means changes to name and number made before session storage are persisted and checkSaved reports the updated object.

Written by the indexing model from the issue text.

Assessment

Tech stack
groovy
Domain
backend, database
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.