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:
- cmd.order.product receives the new value;
- cmd.order.defect also receives the new value (yet it causes a HibernateException later on);
- 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.