Using Grails 2.4.4, I have a .gsp page that returns a parameter that looks like the following:
['update':'Update Budget',
'enteredAcct':['1018', '1200', '5301'],
'enteredOrg':['010', '010', '010'],
'enteredBudget':['100', '500', '200'],
'action':'updateBudget',
'format':null,
'controller':'orgs']
The number of values in the key's List is variable from 1..x (they will all be the same size though). Is there a cleaner way to save this information to the database?
My .gsp is:
<g:each in="${orgnList}" var="orgs">
<tr>
<td> ${orgs.acctCode}</td>
<td> <g:textField name="enteredBudget" value="${orgs.budget}"/></td>
<td> <g:hiddenField name="enteredOrg" value="${orgs.orgCode}"/> </td>
<td> <g:hiddenField name="enteredAcct" value="${orgs.acctCode}"/></td>
</tr>
</g:each>
Which displays an account and budget for a given Org and allows you to enter a new value for the "budget" only.
My controller is as follows:
(0..params.enteredAcct.size()-1).each{new Budget(
orgCode: params.enteredOrg[it],
acctCode: params.enteredAcct[it],
budget: params.enteredBudget[it],
activityDate: new Date()
).save(flush:true)}
Which works, however if my params only has 1 value for each key, then the closure doesn't work because enteredAcct (or any other key) is no longer a list, but a String.
I am mainly just looking to see if there is a more efficient way to save a returned params Map that has a list of values for each key, bindData doesn't seem to work in this case, which is probably expected.
I could always check if params.enteredAcct instanceof List then use that closure, and if not, just persist the single values, but I feel like there is a lot of noise in this code. I also don't like having to use flush:true if at all possible, but with that closure, the .save() won't seem to work unless the flush is forced.
Thanks
For this cases there's the method list in GrailsParameterMap.
params.enteredAcct // could be String or String[]
params.list('enteredAcct') // Always a List<String>
Another benefit of using it is that, for the "is multiple" case, you get list instead of an array (at least in Grails 2.2.x the original parameter value is an array).
As for the flush, you don't need it - but the data won't hit the database until the session is flushed, meanwhile the objects will remain in the Hibernate's session. A session is opened per request, so it's closed (and flushed) when the request is finished. It also gets flushed whenever a read operation is requested (DomainClass.findBy...
, DomainClass.get...
, etc). Flushing all the time is less performant, so I would avoid it.
You can use save(failOnError:true)
though, to ensure the operation fails as soon as possible when provided with invalid data. And probably move it to a service to use their transactional features.