Search code examples
grailsgrails-orm

Saving Set of Domains For a Parent


I have the following Domains:

class Attribute {
  static hasMany = [attributeParameters: AttributeParameter]
}

class AttributeParameter {

   String value
   Integer sequenceNo
   static belongsTo = [attribute: Attribute]
}

I have a form where I want to display all the existing AttributeParameters for an Attribute and allow the user to populate their values and click Save. On Save, each AttributeParameter (which already has an ID) needs to be updated.

I'm currently drawing a blank on how I need to create the HTML for this to work. I've tried this:

Code simplified to clarity:

<form>
  <input type="hidden" name="attributeParameters[0].id" value="1" />
  <input type="text" name="attributeParameters[0].value" value="1234567" />
  <input type="hidden" name="attributeParameters[1].id" value="2" />
  <input type="text" name="attributeParameters[1].value" value="name" />
</form>

def save() {
  def attribute = Attribute.get(params.id)
  attribute.properties = params
}

and it populates the collection correctly, but it doesn't work because the AttributeParameter isn't being fetched before the save, so it is failing with an error:

A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: com.foo.Attribute.attributeParameters

UPDATE:

I modified the HTML to the following:

<form>
  <input type="hidden" name="attributeParameters.id" value="1" />
  <input type="text" name="attributeParameters.value" value="1234567" />
  <input type="hidden" name="attributeParameters.id" value="2" />
  <input type="text" name="attributeParameters.value" value="name" />
</form>

And the controller:

params.list('attributeParameters').each {
   def ap = AttributeParameter.get(it.id)
   ap.value = it.value
   ap.save()
}

This works. My only concern is the order in which the parameters come in. If they always come into the params object in the same order they show up on the form, then I should be ok. but if they ever come in differently, I could be modifying the value of the wrong AttributeParameter.

So still looking for a better way or some sort of verification that they params will always be first in-first out.

UPDATE 2:

I ran across this post and it is what I want but I cannot change Attribute.attributeParameters into a List. They need to stay as a Set.


Solution

  • Could you do something like this:

    <form>
      <input type="text" name="attributeParameter.1" value="1234567" />
      <input type="text" name="attributeParameter.2" value="name" />
    </form>
    

    Where you create the names and values dynamically from each AttributeParameter:

    <g:textField name="attributeParameter.${attributeParameterInstance.id}" value="${attributeParameterInstance.value}" />
    

    And then in your controller

    params.attributeParameter.each {id, val->
        def ap = AttributeParameter.get(id)
        ap.value = val
        ap.save()
    }
    

    That way you have the actual id of each parameter directly and it wouldn't matter which order they were processed.