Problem with Grails GORM - grails

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.

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 behavior method AddTo*

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.

Grails querying the database

I am trying to query a database within grails using:
def per = User.get(springSecurityService.principal.id)
def query = Post.whereAny {
author { username == per.username }
}.order 'dateCreated', 'desc'
messages = query.list(max: 10)
My User is in a User domain and in the Post domain I have:
String message
User author
Date dateCreated
when I run this query its empty every time my method in the controller for populating the database is:
def updateStatus() {
def status = new Post(message: params.message)
System.out.println("test " + params.message)
status.author = User.get(springSecurityService.principal.id)
status.save()
}
I am very new at quering databases in grails so if anyone could recommend some reading this would be good too.
Thanks
New version of spring-security-core plugin add methods to you controller, thus you can replace:
def per = User.get(springSecurityService.principal.id)
def query = Post.whereAny {
author { username == per.username }
}.order 'dateCreated', 'desc'
messages = query.list(max: 10)
with
messages = Post.findAllByAuthor(principal, [sort: 'dateCreated', order 'desc', max: 10])
Without declaring springSecurityService
You can replace the updateStatus action with:
def updateStatus(){
def status = new Post(message: params.message, author: principal)
status.save()
}
Empty query may be resolved with:
def updateStatus() {
def status = new Post(message: params.message)
System.out.println("test " + params.message)
status.author = User.get(springSecurityService.principal.id)
status.save(flush: true)
}
This may help you find the data later as the save() just gives your hibernate context the instruction to persist the data, but does not force hibernate to do it at that moment. passing flush:true will force data to be persisted immediately. Also status.save(failOnError:true) will reveal if your domain object properties have validation issues preventing the domain instance from being saved at all to the database (by throwing an Exception). You can use both if desired:
def updateStatus() {
def status = new Post(message: params.message)
System.out.println("test " + params.message)
status.author = User.get(springSecurityService.principal.id)
status.save(flush: true, failOnError: true)
}
hope that helps.
You can set flush and failOnError: true globally as well in grails-app/conf/Config.groovy:
grails.gorm.failOnError=true
grails.gorm.autoFlush=true

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

Saving associated domain classes in Grails

I'm struggling to get association right on Grails. Let's say I have two domain classes:
class Engine {
String name
int numberOfCylinders = 4
static constraints = {
name(blank:false, nullable:false)
numberOfCylinders(range:4..8)
}
}
class Car {
int year
String brand
Engine engine = new Engine(name:"Default Engine")
static constraints = {
engine(nullable:false)
brand(blank:false, nullable:false)
year(nullable:false)
}
}
The idea is that users can create cars without creating an engine first, and those cars get a default engine. In the CarController I have:
def save = {
def car = new Car(params)
if(!car.hasErrors() && car.save()){
flash.message = "Car saved"
redirect(action:index)
}else{
render(view:'create', model:[car:car])
}
}
When trying to save, I get a null value exception on the Car.engine field, so obviously the default engine is not created and saved. I tried to manually create the engine:
def save = {
def car = new Car(params)
car.engine = new Engine(name: "Default Engine")
if(!car.hasErrors() && car.save()){
flash.message = "Car saved"
redirect(action:index)
}else{
render(view:'create', model:[car:car])
}
}
Didn't work either. Is Grails not able to save associated classes? How could I implement such feature?
I think you need a belongsTo in your Engine ie
static belongsTo = [car:Car]
Hope this helps.
For what is worth, I finally nailed it.
The exception I got when trying to save a car was
not-null property references a null or
transient value
It was obvious that the engine was null when trying to save, but why? Turns out you have to do:
def car = new Car(params)
car.engine = new Engine(name: "Default Engine")
car.engine.save()
Since engine doesn't belongs to a Car, you don't get cascade save/update/delete which is fine in my case. The solution is to manually save the engine and then save the car.

Resources