1

I'm trying to use a Domain (Order) with 3 Single-ended Associations (Product, Defect & Solution) in a CommandObject to perform an update, and I'm receiving 3 different behaviours:

  1. cmd.order.product receives the new value;
  2. cmd.order.defect also receives the new value (yet it causes a HibernateException later on);
  3. cmd.order.solution is utterly ignored;

Ok, this is the environment:

  • Groovy: 2.3.7
  • JVM: 1.7.0_71 Vendor: Oracle Corporation OS: Mac OS X
  • Grails 2.2.4

And these are the actors:

class Order {

    Product product
    Defect defect
    Solution solution

    static constraints = {
        product nullable: true        
        defect nullable: true
        solution nullable: true, validator:  { val, obj, errors ->
            if (val && !obj.defect) {
                errors.rejectValue 'solution', 'defect.dequired', [val.name] as Object[], null
            }
        }
    }
}

@Validateable
class OrderCommand {

    Order order

    static constraints = {
        order nullable:false
    }
}

class OrderController {
    ...
    def update(final OrderCommand cmd) {

        def instance = cmd.order

        println params

        log.debug "cmd.errors: '${cmd.errors}'"
        log.debug "instance.errors: '${instance.errors}'"
        log.debug "instance.product.id: '${instance.product?.id}', params.order.product.id: '${params.order?.product?.id}'"
        log.debug "instance.defect.id: '${instance.defect?.id}', params.order.defect.id: '${params.order?.defect?.id}'"
        log.debug "instance.solution.id: '${instance.solution?.id}', params.order.solution.id: '${params.order?.solution?.id}'"

        if(!cmd.hasErrors() && instance.validate()) {
           instance = instance.save validate:false, failOnError:true
           this.flashDefaultMessageUpdated Order.class
        }
    }
    ...
}

And this is the form rendered (sorta..):

<form action="/foo/order/update" method="post">

    <input type="hidden" id="orderId" name="order.id" value="257132">

    <select id="product" name="order.product.id">
        <option value="null">Select…</option>
        <option value="36">PRODUCT 1</option>
        ...
    </select>

    <select id="defect" name="order.defect.id">
        <option value="null">Select…</option>
        <option value="49">DEFECT 1</option>
        ...
    </select>

    <select id="solution" name="order.solution.id">
        <option value="null">Select…</option>
        <option value="6">SOLUTION 1</option>
        ...
    </select>
    ...
</form>

Now, given an existent Order, for "instance" (HA!):

def orderInstance = Order.get 257132l
println orderInstance 
//[id:257132, product:[id:36], defect:[id:4], solution:null]

After the submit to '/foo/order/update', the parameters received are:

println params
/*
[action:update, controller:order, 
               order:[
                id:257132,
                solution.id:1, 
                solution:[id:1], 
                defect.id:49, 
                defect:[id:49], 
                product.id:31, 
                product:[id:31]
            ],
order.defect.id:49, 
order.id:257132, 
order.product.id:31, 
order.solution.id:1, 
version:33]
*/

But the object is binded kinda weirdly, check this out:

log.debug..
/*
//DEBUG cmd.errors: '0 errors'
//DEBUG instance.errors: '0 errors'
//DEBUG instance.product.id: '31',    params.order.product.id: '31' [OK]
//DEBUG instance.defect.id: '49',     params.order.defect.id: '49' [OK]
//DEBUG instance.solution.id: 'null', params.order.solution.id: '1' [??]
*/

That is, both the product and the defect new values were received correctly, whereas the solution new value was simply ignored.

Oddly enough, when trying to perform the update, the following exception is thrown:

org.hibernate.HibernateException: 
identifier of an instance of com.foo.domain.Defect was altered from 4 to 49

Any ideas?

I fear for my sanity already.

Cheers.

  • 3
    That looks like a bug in the data binder. If you file an issue at https://github.com/grails/grails-core/issues and provide a simple sample app which demonstrates the problem we can get that straightened out. Thanks for the feedback. – Jeff Scott Brown Aug 13 '15 at 02:18
  • Hi Jeff, thanks for your reply! So, I've created a new project from scratch and I couldn't simulate the problem, what leads me to believe that it might be something in my environment. If you were to try to sort this out, what would you do? I mean, is there any log that you would enable or process that you would follow? Curiously, in my new project, I have a slightly different problem: Seemingly, I cannot bind the Order instance inside the OrderCommand. Is there any limitation or restriction to binding instances of the same name of the command or something like this? – Rogério R. Alcântara Aug 14 '15 at 11:08
  • Trying to sort this out, I had a kinda epiphany: this is not the correct way to use CommandObjects, isn't it? Rather, I should try to map only the properties that can be changed by the page and avoid binding everything that comes from the form to the main object, right? In the face of this new mindset, I decided to change my approach and now I'm creating a Command Object with only the properties of the Order - and not having the Order instance itself, which I believe is more adequate, right? – Rogério R. Alcântara Aug 14 '15 at 11:32

0 Answers0