Grails behavior method AddTo* - grails

I'm an instability in my addTo* method which I have a record that constantly have to make the relationship information in one instance . The problem is that when I place multiple inserts in a short time , they cease to be persisted in the database and not after a they return , they are simply discarded time.
My simple class is ' Occurrence ' and ' Monitoring ' , whenever I make a call I have to register it and it occurred on and after 2 consecutive records the 3rd no longer persists in the database and I lose the record .
Class Occurrence implements Serializable{
...
hasMany = [accompaniments: Monitoring]
...
}
Class Monitoring implements Serializable{
...
belongsTo = [occurrence : Occurrence]
...
}
Have the controller looks like this:
def regMonitoring(Long id){
def chamadoInstance = Occurrence.get(id)
if (!chamadoInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'Occurrence .label', default: 'Occurrence '), id])
return
}
chamadoInstance.status = StatusChamado.findByCodigo("MOV")
if (!chamadoInstance.save(flush: true)) {
render(view: "editMonitoring", model: [chamadoInstance: chamadoInstance])
return
}
def mov = chamadoService.regMonitoring("") //returns an instance of Customer with preset output values ​​.
chamadoInstance.addToAccompaniments (mov)
redirect(action: "showChamado", id: chamadoInstance.id)
}

Add in a save of your domain instance after you add to the collection.
chamadoInstance.addToAccompaniments (mov)
chamadoInstance.save(flush: true)
This should solve the issue.

Related

Preventing a write to the database from Grails controller

I have a small Grails project I'm writing as a learning exercise. It gathers some user input from a form (eg. enter two numbers to add), then it calls a service to process that data (eg. add the two numbers), and finally it shows the results on a another page.
When I turned on SQL logging I noticed that the data the user is entering is being saved to the database before the call to the service method inside the controller.
How do I prevent this? I would like ONE write to the database after the call to the service method is complete and there are no errors.
Save method from controller code:
def save() {
def myInstance = new myDomainClass(params)
myInstance.sessionId = session.id
myService argh = new myService()
// wtf does this do?
if (!myInstance.save(flush: true)) {
render(view: "create", model: [myInstance: myInstance])
return
}
// Execute the api and process the results. what is writing the user input to the database before this call?!?!?!?!
def results1 = argh.executeApi(myInstance)
// if the results are null throw an error
if (results1 == null) {
flash.message = message(code: 'api.null.error')
render(view: "create", model: [apiInstance: apiInstance])
return
} else {
forward(action: "list", id: 2, model: [apiInstanceList: Api.list(params), apiInstanceTotal: Api.count()])
}
}
Pointers or help appreciated.
Calling .save(flush:true) will automatically save the myInstance instance to the database at that point. You will want to move the .save(flush:true) to after the service method, and since you said you wanted to make sure there were no errors, you would want to add it to your conditional:
def save() {
def myInstance = new myDomainClass(params)
myInstance.sessionId = session.id
myService argh = new myService()
// Execute the api and process the results. what is writing the user input to the database before this call?!?!?!?!
def results1 = argh.executeApi(myInstance)
// if the results are null throw an error
if (results1 == null) {
flash.message = message(code: 'api.null.error')
render(view: "create", model: [apiInstance: apiInstance])
return
} else {
// save here when you know there are no errors
if (!myInstance.save(flush: true)) {
render(view: "create", model: [myInstance: myInstance])
return
}
forward(action: "list", id: 2, model: [apiInstanceList: Api.list(params), apiInstanceTotal: Api.count()])
}
}

Grails update() cannot locate record, show() and edit() can

I've got a fairly simple Grails app against a DB2 database. Everything works fine except when I try to update a record. show() and edit() are able to find the record , but the update fails saying that it cannot be located. Here's the edit:
def edit()
{
def flatAdjustmentInstance = FlatAdjustment.get( new FlatAdjustment(compPayeeID: params["compPayeeID"], effectiveQuarterBeginDate: params["effectiveQuarterBeginDate"]) ) //here are your inbound params
if(!flatAdjustmentInstance)
{
flash.message = "MRI Modifier Record not found with ${params}"
redirect(action:"list")
}
else
{
return [ flatAdjustmentInstance: flatAdjustmentInstance]
}
}
Now the update()
def flatAdjustmentInstance = FlatAdjustment.get( new FlatAdjustment(compPayeeID: params["compPayeeID"], effectiveQuarterBeginDate: params["effectiveQuarterBeginDate"]) ) //here are your inbound params
//def flatAdjustmentInstance = new FlatAdjustment(compPayeeID: params["compPayeeID"], effectiveQuarterBeginDate: params["effectiveQuarterBeginDate"])
if (!flatAdjustmentInstance)
{
flash.message = message(code: 'default.not.found.message', args: [message(code: 'flatAdjustment.label', default: 'FlatAdjustment'), params])
redirect(action: "list")
return
}
As I said, all controller methods/closures create the instance of the domain object in the same way and all work correctly except for update(). Any ideas?
.get() retrieves an existing object based on its ID. You cannot pass a new object to that method.
FlatAdjustment flatAdjustmentInstance = FlatAdjustment.findByCompPayeeIDAndEffectiveQuarterBeginDate(params.compPayeeID, params.date("effectiveQuarterBeginDate", "INSERTYOURDATEFORMATHERE"))
I figured this one out, and it was a really bone-headed mistake. The form I had created was passing in the compPayeeID, but since the field is not editable by the user, I changed it from an input to a textField. That meant is was no longer being passed in with the grails params object. I changed it back, set the field to read only, and now all is well.

Grails - save the transient instance before flushing grails Error?

I am currently developing a Grails Application and I am working with the Spring Security and UI plug-ins. I have created the relationship between the User Class and another Area Class that I have which can be seen below:
User Class:
class User {
transient springSecurityService
String username
String email
String password
boolean enabled
boolean accountExpired
boolean accountLocked
boolean passwordExpired
static belongsTo = [area:Areas]
.......
}
Area Class:
class Areas {
String name
static hasMany = [users:User]
}
As you can see from the classes one user can be linked to one area but an area might have many users. This all works fine and when I bootstrap the application all data gets added correctly. however I get the following error when i try to use a form to create a new user:
object references an unsaved transient instance - save the transient instance before flushing: com.website.Area
below is the controller code I am using to save the information:
def save = {
def user = lookupUserClass().newInstance(params)
if (params.password) {
String salt = saltSource instanceof NullSaltSource ? null : params.username
user.password = springSecurityUiService.encodePassword(params.password, salt)
}
if (!user.save(flush: true)) {
render view: 'create', model: [user: user, authorityList: sortedRoles()]
return
}
addRoles(user)
flash.message = "${message(code: 'default.created.message', args: [message(code: 'user.label', default: 'User'), user.id])}"
redirect action: edit, id: user.id
}
and here is a sample of what the GSP looks like:
<table>
<tbody>
<s2ui:textFieldRow name='username' labelCode='user.username.label' bean="${user}"
labelCodeDefault='Username' value="${user?.username}"/>
<s2ui:passwordFieldRow name='password' labelCode='user.password.label' bean="${user}"
labelCodeDefault='Password' value="${user?.password}"/>
<s2ui:textFieldRow name='email' labelCode='user.email.label' bean="${user}"
labelCodeDefault='E-Mail' value="${user?.email}"/>
<s2ui:textFieldRow readonly='yes' name='area.name' labelCode='user.area.label' bean="${user}"
labelCodeDefault='Department' value="${area.name}"/>
<s2ui:checkboxRow name='enabled' labelCode='user.enabled.label' bean="${user}"
labelCodeDefault='Enabled' value="${user?.enabled}"/>
<s2ui:checkboxRow name='accountExpired' labelCode='user.accountExpired.label' bean="${user}"
labelCodeDefault='Account Expired' value="${user?.accountExpired}"/>
<s2ui:checkboxRow name='accountLocked' labelCode='user.accountLocked.label' bean="${user}"
labelCodeDefault='Account Locked' value="${user?.accountLocked}"/>
<s2ui:checkboxRow name='passwordExpired' labelCode='user.passwordExpired.label' bean="${user}"
labelCodeDefault='Password Expired' value="${user?.passwordExpired}"/>
</tbody>
</table>
I have looked into this and I believe it is the way I am trying to save a GORM Object and I should maybe save the parent(Area) before trying to save the user. However the Area will always exist before the user can be created so I don’t need the area to be created again, how do I handle this? I tried the "withTransaction" function with little success as well
I would really appreciate some help on this if possible.
Thanks
EDIT ......
I have tracked the issue to this line in the Controller:
RegistrationCode registrationCode = springSecurityUiService.register(user, command.password, salt)
This say to me that this function is calling a save function for the user object, however with the relationships in place it needs to save the Area first. Does anyone know SpringSecurityUi in order to help me on this?
Thanks
The error message you see
object references an unsaved transient instance - save the transient instance before flushing: com.website.Area
... happens when you're trying to save a non-existent parent (i.e Area) entity from a child (i.e User) entity. It's possible that error is happening in the RegistrationController.register method as you pointed out, if that's where you're saving a new User.
RegistrationCode registrationCode = springSecurityUiService.register(user, command.password, salt)
You just need to update the RegistrationCode.register method with logic to assign the Area to a User (assuming the Area already exists) before the register call - below is a quick example.
class RegistrationController ..
..
def area = Area.findByName(command.areaName)
def user = lookupUserClass().newInstance(email: command.email, username: command.username,
accountLocked: true, enabled: true, area: area)
RegistrationCode registrationCode = springSecurityUiService.register(user, command.password, salt)
A couple of notes:
you are passing back "area.name" from your gsp view, so you'll need to update/override the RegisterCommand to include the Area name
is your use of Area "name" as an identifier safe? In your class definition you don't have constraints to indicate that "name" will be unique. Maybe passing back an Area id from your view is safer
ideally you should handle the Area lookup with a custom property editor - here is an example: Grails command object data binding
Anyways, hope that helps.
Try to turn bi-directional dependency to the other side
class Areas {
String name
static belongsTo = [User]
static hasMany = [users:User]
}
Don't forget to remove belongsTo from User
class Areas {
String name
static belongsTo = [User]
static hasMany = [users:User]
}

Problem with Grails GORM

I am developing an application which queries data from an XML file and creates multiple objects with that data.
class Search {String artist}
class Performance {static belongsTo = [events:Event, artists:Artist]}
class Location {static belongsTo = [events:Event]}
class Event {static hasMany = [performances:Performance]}
class Artist {static hasMany = [performances:Performance]}
This are the domain classes (for the sake of simplicity only relationships are shown).
Then I want to create instances of this objects when the user inserts a new artist in the SearchController. I tried to do that with the following code for the save closure in the SearchController but it seems that it's not working. The resultList is a Map with the values queried from the XML file.
def save = {
def searchInstance = new Search(params)
def resultsList = searchService.lastFmVenues(params.artist)
resultsList.each{
def performanceInstance = new Performance()
def locationInstance = new Location(venue:it.venue, street:it.street, city:it.city, postcode:it.postalcode, country:it.country, lat:it.lat, lng:it.lng)
def artistInstance = new Artist(name:params.artist).addToPerformances(performanceInstance)
def eventInstance = new Event(eventId:it.eventID, title:it.eventTitle, date:it.date, location:locationInstance)
if (searchInstance.save(flush:true) && eventInstance.save(flush: true) && artistInstance.save(flush: true) && locationInstance.save(flush: true) && performanceInstance.save(flush:true)) {
flash.message = "${message(code: 'default.created.message', args: [message(code: 'search.label', default: 'Search'), searchInstance.id])}"
}
else {
render(view: "create", model: [searchInstance: searchInstance])
}
}
redirect(action: "show", id: searchInstance.id)
}
Any ideas?
Thank you.
Try saving your objects with save(failOnError: true). This will cause grails to throw an exception if the objects don't validate. The default behavior is to simply return false from the save method.
You can make failOnError the default behavior by setting grails.gorm.failOnError=true in your Config.groovy, but I wouldn't recommend it for anything besides troubleshooting.

Why are setters in Grails called twice on save?

Look at the following Grails domain class, which modifies a value within a setter, if the object is saved the first time (if it has no id):
class Idtest {
String name
void setName(String name) {
if(!this.id)
this.name = name + "TEST"
else
this.name = name
}
}
If I generate views and controller with generate-all, start the app, and enter "hello" in the generated form, "helloTESTTEST" is saved.
The save function looks like this:
def save = {
def idtestInstance = new Idtest(params)
if (idtestInstance.save(flush: true)) {
flash.message = "${message(code: 'default.created.message', args: [message(code: 'idtest.label', default: 'Idtest'), idtestInstance.id])}"
redirect(action: "show", id: idtestInstance.id)
}
else {
render(view: "create", model: [idtestInstance: idtestInstance])
}
}
Why is the setter called twice?
Instead of doing
if(!this.id){ }
You should use beforeInsert()
GORM Advanced Features
I believe it is called once when you create the object and it is saved
Then it would be called again when you retrieved the object from the database.
So..
On saving to to the database the property is set, lets assume a counter = counter + 1. so now one is saved to the database.
When you retrieve the object from the database, the domain object setter will be called again thereby incrementing the counter again counter++
This is all an assumption since the there is no controller code here for us to see how you are creating and or saving the objects so dont bash me if I am completely off

Resources