EDIT: onload() method changed to afterLoad(): Otherwise objects might not be passed properly to the map.
I am currently using some domain classes with a lot of dynamic, complex properties, that I need to persist and update regularly.
I keep these in a Map structure for each class since this makes it easy for referencing in my controllers etc.
However, since Grails does not seem to be able to persist complex property types like List and Map in the DB I am using the following approach to achieve this via JSON String objects:
class ClassWithComplexProperties {
Map complexMapStructure //not persisted
String complexMapStructureAsJSON //updated and synched with map via onload,beforeInsert,beforeUpdate
static transients = ['complexMapStructure']
def afterLoad() { //was previously (wrong!): def onLoad() {
complexMapStructure=JSON.parse(complexMapStructureAsJSON)
}
def beforeInsert() {
complexMapStructureAsJSON= complexMapStructure as JSON
}
def beforeUpdate() {
complexMapStructureAsJSON= complexMapStructure as JSON
}
static constraints = {
complexMapStructureAsJSON( maxSize:20000)
}
}
This works well as long I am only loading data from the DB, but I run into trouble when I want to save back my changes to the DB. E.g. when I do the following
/* 1. Load the json String, e.g. complexMapStructureAsJSON="""{
data1:[[1,2],[3,4]],//A complex structure of nested integer lists
data1:[[5,6]] //Another one
}""" :
*/
ClassWithComplexProperties c=ClassWithComplexProperties.get(1)
// 2. Change a value deep in the map:
c.complexMapStructure.data1[0][0]=7
// 3. Try to save:
c.save(flush:true)
This will usually not work, since, I guess(?), GORM will ignore the save() request due to the fact that the map itself is transient, and no changes are found in the persisted properties.
I can make it work as intended if I hack step 3 above and change it to:
// 3.Alternative save:
complexMapStructureAsJSON="" //creating a change in persisted property (which will be overwritten anyway by the beforeUpdate closure)
c.save(flush:true)
To me this is not a very elegant handling of my problem. The questions:
- Is there a simpler approach to persist my complex, dynamic map data?
- If I need to do it the way I currently do, is there a way to avoid the hack in step 3 ?
beforeValidate
event instead ofbeforeInsert
andbeforeUpdate
? – Flyingbindable: true
in the constraints, to be able to receive data from form POST and from the map constructor, while the JSON field is best declaredbindable: false
. – Feme