Setting Grails domain id in Bootstrap.groovy - grails

Is it possible to explicitly set the id of a domain object in Grails' Bootstrap.groovy (or anywhere, for that matter)?
I've tried the following:
new Foo(id: 1234, name: "My Foo").save()
and:
def foo = new Foo()
foo.id = 1234
foo.name = "My Foo"
foo.save()
But in both cases, when I print out the results of Foo.list() at runtime, I see that my object has been given an id of 1, or whatever the next id in the sequence is.
Edit:
This is in Grails 1.0.3, and when I'm running my application in 'dev' with the built-in HSQL database.
Edit:
chanwit has provided one good solution below. However, I was actually looking for a way to set the id without changing my domain's id generation method. This is primarily for testing: I'd like to be able to set certain things to known id values either in my test bootstrap or setUp(), but still be able to use auto_increment or a sequence in production.

Yes, with manually GORM mapping:
class Foo {
String name
static mapping = {
id generator:'assigned'
}
}
and your second snippet (not the first one) will do the job (Id won't be assigned when passing it through constructor).

What I ended up using as a workaround was to not try and retrieve objects by their id. So for the example given in the question, I changed my domain object:
class Foo {
short code /* new field */
String name
static constraints = {
code(unique: true)
name()
}
}
I then used an enum to hold all of the possible values for code (which are static), and would retrieve Foo objects by doing a Foo.findByCode() with the appropriate enum value (instead of using Foo.get() with the id like I wanted to do previously).
It's not the most elegant solution, but it worked for me.

As an alternative, assuming that you're importing data or migrating data from an existing app, for test purposes you could use local maps within the Bootstrap file. Think of it like an import.sql with benefits ;-)
Using this approach:
you wouldn't need to change your domain constraints just for
testing,
you'll have a tested migration path from existing data, and
you'll have a good data slice (or full slice) for future integration tests
Cheers!
def init = { servletContext ->
addFoos()
addBars()
}
def foosByImportId = [:]
private addFoos(){
def pattern = ~/.*\{FooID=(.*), FooCode=(.*), FooName=(.*)}/
new File("import/Foos.txt").eachLine {
def matcher = pattern.matcher(it)
if (!matcher.matches()){
return;
}
String fooId = StringUtils.trimToNull(matcher.group(1))
String fooCode = StringUtils.trimToNull(matcher.group(2))
String fooName = StringUtils.trimToNull(matcher.group(3))
def foo = Foo.findByFooName(fooName) ?: new Foo(fooCode:fooCode,fooName:fooName).save(faileOnError:true)
foosByImportId.putAt(Long.valueOf(fooId), foo) // ids could differ
}
}
private addBars(){
...
String fooId = StringUtils.trimToNull(matcher.group(5))
def foo = foosByImportId[Long.valueOf(fooId)]
...
}

Related

Grails : id generator using assigned and falling back to sequence if unassigned

I am working with Grails 3.2.8. I would like to allow both options when generating an id. Is there a way to use assigned and falling back to sequence if unassigned? I tried getting the next id within a constructor and setting id there but running into issues. Any help/guidance would be most appreciated.
class Foo {
static mapping = {
id generator:'assigned'
}
}
vs
class Foo {
static mapping = {
id generator:'sequence'
}
}
Ive tried using mapping set to assigned and setting the id within the domain constructor of beforeValidate function. Neither are working for me. Examples below.
class Foo{
Foo(){
def id = Foo.find("from Foo order by id desc")
id = id ? id : 0
this.id = id
}
static mapping = {
id generator:'assigned'
}
}
class Foo{
def beforeValidate() {
def id = Foo.find("from Foo order by id desc")
id = id ? id : 0
this.id = id
}
static mapping = {
id generator:'assigned'
}
}
Thanks in advance for your help.
Is there a way to use assigned and falling back to sequence if
unassigned?
No, not directly anyway. You could use assigned and when you wanted to fall back on the sequence you could send a query to the database to retrieve the next sequence value and then assign it yourself. I think that is probably as close as you can probably get.
First of all, you need to understand HQL; in your examples you are returning Foo not id, so it's clearly wrong.
Second, you shouldn't depend on the table for next value of id, because it's not guaranteed to be correct -- you might face id is not unique kinda errors.
Third, you aren't incrementing the id, this way you will end up getting the same, most likely 0, every time.
Here is what you can do, use database sequence -- depends on the database.
"select id_seq.nextval from dual" // for Oracle
Finally, it's a very bad idea -- unless you are having a very good reason for it.

Grails - Command object, service method

I'm not a programming savvy person, so please bear with me.
I've read blog entries and docs about command object. I've never used it and was wondering if I should. (I probably should...)
My project requires parsing, sorting, calculating, and saving results into database when users upload files.
So according to one of the blog entries I read and its corresponding github code,
1) SERVICE should receive file uploads, parse uploaded files (mainly docs and pdfs), sort parsed data using RegEx, and calculate data,
2) COMMAND OBJECT should call SERVICE, collect results and send results back to controller, and save results into the database,
3) CONTROLLER should receive request from VIEW, get results from COMMAND OBJECT, and send results back to VIEW.
Did I understand correctly?
Thanks.
I found this to be the best setup. Here is an example that I use on production:
Command Object (to carry data and ensure their validity):
#grails.validation.Validateable
class SearchCommand implements Serializable {
// search query
String s
// page
Integer page
static constraints = {
s nullable: true
page nullable: true
}
}
Controller (directs a request to a Service and then gets a response back from the Service and directs this response to a view):
class SomeController {
//inject service
def someService
def search(SearchCommand cmd) {
def result = someService.search(cmd)
// can access result in .gsp as ${result} or in other forms
render(view: "someView", model: [result: result])
}
}
Service (handles business logic and grabs data from Domain(s)):
class SomeService {
def search(SearchCommand cmd) {
if(cmd.hasErrors()) {
// errors found in cmd.errors
return
}
// do some logic for example calc offset from cmd.page
def result = Stuff.searchAll(cmd.s, offset, max)
return result
}
}
Domain (all database queries are handled here):
class Stuff {
String name
static constraints = {
name nullable: false, blank: false, size: 1..30
}
static searchAll(String searchQuery, int offset, int max) {
return Stuff.executeQuery("select s.name from Stuff s where s.name = :searchQuery ", [searchQuery: searchQuery, offset: offset, max:max])
}
}
Yes, you understood it correctly except the one thing: command object shouldn't save the data to DB - let service to do that. The other advantage of command object is data binding and validation of data from the client. Read more about command objects here grails command object docs
You can also find helpful information regarding your question in this article
grails best practices
I guess not. Its not really related to whether the save is done in a service it should always attempt to carry out complex stuff and specifically db stuff in a service. so that is regardless. I tend to not use command object but have got hooked on helper classes aka beans that sit in src/main/groovy and do all of the validation and formatting. I just did a form and in it has feedback and reason.
Initially I thought I would get away with
def someAction(String feedback, String reason) {
someService.doSomething(feedback,reason)
}
But then I looked closed and my form was firstly a textarea then the selection objects were bytes so above was not working and to simply fix it without adding the complexity to my controller/service I did this:
packe some.package
import grails.validation.Validateable
class SomeBean implements Validateable {
User user
byte reason
String feedback
static constraints = {
user(nullable: true)
reason(nullable:true, inList:UsersRemoved.REASONS)
feedback(nullable:true)
}
void setReason(String t) {
reason=t as byte
}
void setFeedback(String t) {
feedback=t?.trim()
}
}
Now my controller
class SomeController {
def userService
def someService
def doSomething(SomeBean bean){
bean.user = userService.currentUser
if (!bean.validate()) {
flash.message=bean.errors.allErrors.collect{g.message([error : it])}
render view: '/someTemplate', model: [instance: bean,template:'/some/template']
return
}
someService.doSomeThing(bean)
}
}
Now my service
Class SomeService {
def doSomeThing(SomeBean bean) {
if (bean.user=='A') {
.....
}
}
All of that validation would have still had to have been done somewhere, you say no validation but in a good model you should do validation and set things to be stored in proper structures to reduce overloading your db over time. difficult to explain but in short i am talking about your domain class objects and ensuring you are not setting up String something string somethingelse and then not even defining their lenghts etc. be strict and validate
if you have a text area this will be stored in the back end - so you will need to trim it like above - you will need to ensure the input does not exceed the max character of the actual db structure which if not defined will probably be 255
and by doing
static constraints = {
user(nullable: true)
reason(min:1, max:255, nullable:true, inList:UsersRemoved.REASONS)
Has already invalidated it through the bean.validate() in the controller if the user exceeded somehow my front end checks and put in more than 255.
This stuff takes time be patient
Edited to finally add in that example byte - is one to be careful of -
When adding any String or what ever I have started to define the specific like this and in the case of byte if it is a boolean true false - fine if not then define it as a tinyint
static mapping = {
//since there is more than 1 type in this case
reason(sqlType:'tinyint(1)')
feedback(sqlType:'varchar(1000)')
// name(sqlType:'varchar(70)')
}
If you then look at your tables created in the db you should find they have been created as per definition rather than standard 255 varchar which I think is the default for a declared String.

Store and use application configuration settings in database for a Grails application?

we currently use configuration files to store application settings. I was wondering if it is possible to store these settings inside the database and if so how to achieve this?
Greetings
You can store whatever you want in the database and read it out using a Domain class. This is especially useful if you want to be able to make changes to things without having to redeploy new code. But realize that you will incur a database hit every time the property is accessed.
You can set up a ConfigurationService with:
ConfigurationService {
static def configurationValues
def getConfigurationValues() {
if(configurationValues == null) {
refreshConfigurationValues()
}
configurationValues
}
def refreshConfigurationValues() {
configurationValues = //go get the values out of the database
}
}
Then you can add a Controller/Action to force the refresh when necessary
ConfigurationController {
def configurationService
def refreshConfiguration = {
configurationService.refreshConfigurationValues()
render "Ahhh... That's refreshing :)"
}
}
Now you can refresh your config values by invoking: "http://yoururl/appName/configuration/refreshConfiguration"
This is can be done with BootStrap.groovy. So following Jarred's answer, create a domain class of the configuration data you would like to store and then inside the BootStrap.groovy file, put these values. What this does is if the configuration values does not exists, it will create it, if it exists will not do anything.
Then you can access your configuration values using the domain class. I'm assuming you want to do this because grailsApplication.config... can sometimes become unruly.
Domain-Class MyConfig.groovy:
class MyConfig {
String type
String name
String value
}
BootStrap.groovy:
def myConfig = MyConfig.findByName("path") ?: new MyConfig(
type: "Path"
name: "path"
value: "/var/tmp"
).save(failOnError: true)

my own id in GORM

I tried to change the standard 'id' in grails:
calls Book {
String id
String title
static mapping {
id generator:'assigned'
}
}
unfortunately, I soon noticed that this breaks my bootstrap. Instead of
new Book (id:'some ISBN', title:'great book').save(flush:true, failOnError:true)
I had to use
def b = new Book(title:'great book')
b.id = 'some ISBN'
b.save(flush:true, failOnError:true)
otherwise I get an 'ids for this class must be manually assigned before calling save()' error.
but that's ok so far.
I then encountered the same problem in the save action of my bookController. But this time, the workaround didn't do the trick.
Any suggestions?
I known, I can rename the id, but then I will have to change all scaffolded views...
That's a feature of databinding. You don't want submitted data to be able to change managed fields like id and version, so the Map constructor that you're using binds all available properties except those two (it also ignores any value for class, metaClass, and a few others).
So there's a bit of a mismatch here since the value isn't managed by Hibernate/GORM but by you. As you saw the workaround is that you need to create the object in two steps instead of just one.
I can't replicate this problem (used Grails 2.0.RC1). I think it might be as simple as a missing equal sign on your static mapping = { (you just have static mapping {)
Here's the code for a domain object:
class Book {
String id
String name
static mapping = {
id generator:'assigned'
}
}
And inside BootStrap.groovy:
def init = { servletContext ->
new Book(name:"test",id:"123abc").save(failOnError:true)
}
And it works fine for me. I see the id as 123abc.
You need to set the bindable constraint to true for your id prop, e.g.
class Employee {
Long id
String name
static constraints = {
id bindable: true
}
}

Groovy Dynamic List Interaction

I am using an older version of grails (1.1.1) and I am working on a legacy application for a government client.
Here is my question (in psuedo form):
I have a domain that is a Book. It has a sub domain of type Author associated with it (1:many relationship). The Author domain has a firstName and lastName field.
def c = Book.createCriteria()
def booklist = c.listDistinct {
author {
order('lastName', 'asc')
order('firstName', 'asc')
}
}
Let's say I have a list of fields I want to use for an excel export later. This list has both the author domain call and the title of the column I want to use.
Map fields = ['author.lastName' : 'Last Name', 'author.firstName', 'First Name']
How can I dynamically call the following code--
booklist.eachWithIndex(){
key, value ->
println key.fields
}
The intent is that I can create my Map of fields and use a loop to display all data quickly without having to type all of the fields by hand.
Note - The period in the string 'author.lastName' throws an error when trying to output key['author.lastName'] too.
I don't recall the version of Groovy that came with Grails 1.1, but there are a number of language constructs to do things like this. If it's an old version, some things may not be available - so your mileage may vary.
Map keys can be referenced with quotes strings, e.g.
def map = [:]
map."person.name" = "Bob"
The above will have a key of person.name in the map.
Maps can contain anything, including mixed types in Groovy - so you really just need to work around string escapes or other special cases if you are using more complex keys.
You can also use a GString in the above
def map = [:]
def prop = "person.name"
map."${prop}" = "Bob"
You can also get a map of property/value off of a class dynamically by the properties field on it. E.g.:
class Person { String name;String location; }
def bob = new Person(name:'Bob', location:'The City')
def properties = bob.properties
properties.each { println it }

Resources