Grails: setting transient fields in the map constr

2019-01-27 00:51发布

问题:

I'm trying to persist Maps of properties as single JSON-encoded columns, as shown in this question.

The problem I'm having is that apparently transient properties cannot be set in the default map constructor. Given any transient field:

class Test {
    //...
    String foo
    static transients = ['foo']
}

It seems that the map constructor (which Grails overrides in various ways) simply discards transient fields:

groovy:000> t = new Test(foo:'bar')
===> Test : (unsaved)
groovy:000> t.foo
===> null

While direct assignment (through the setter method) works as expected:

groovy:000> c.foo = 'bar'
===> bar
groovy:000> c.foo
===> bar

Is there a way to make the map constructor accept transient fields?


Or rather: is there a better way to persist a Map as a single JSON-encoded DB field, rather than the method shown in the linked question?

Here's the complete example:

import grails.converters.JSON

class JsonMap {
    Map data
    String dataAsJSON

    static transients = ['data']
    def afterLoad()      { data = JSON.parse(dataAsJSON) }
    def beforeValidate() { dataAsJSON = data as JSON }
}

I can set data using the setter (which will then be converted into dataAsJSON) but not using the map constructor.

回答1:

The map constructor in GORM uses the data binding mechanism, and transient properties are not data-bindable by default. But you can override this using the bindable constraint

class Test {
    //...
    String foo
    static transients = ['foo']

    static constraints = {
        foo bindable:true
    }
}


回答2:

I've also replied to your original question, that you don't need json conversion to achieve what you need. However, If you need json conversion badly, why don't you implement it in your getters/setters?

class Test {
    String propsAsJson

    static transients = ['props']

    public Map getProps() {
        return JSON.parse(propsAsJson)
    }

    public void setProps(Map props) {
        propsAsJson = props as JSON
    }
}

//So you can do
Test t = new Test(props : ["foo" : "bar"])
t.save()

In this way you encapsulate the conversion stuff, and in DB you have your properties as Json.



回答3:

You can simplify your case by adding the JSON-conversion methods to your domain class, they should have nothing to do with GORMing:

class Test {
    String title

    void titleFromJSON( json ){ 
      title = json.toStringOfSomeKind()
    }

    def titleAsJSON(){ 
      new JSON( title )
    }

}