Benefits of using Insert flag in Grails save() - grails

What are the benefits of using the grails insert flag when saving a domain class?
Here is an example:
Lets say I have a Domain Object FooBar:
FooBar foo = FooBar.find("foo")?: new FooBar(id:"foo")
foo.bar = "bar"
foo.save()
Would it be better do do something more like this:
boolean insertFlag
FooBar foo = FooBar.find("foo")
if(foo == null){
insertFlag = false
}else {
foo = new FooBar(id:"foo")
insertFlag = true
}
foo.bar = "bar"
foo.save(insert: insertFlag)
I was thinking that the save would run smoother somehow with the insert flag verses not having it.

insert inside save is highly useful if you have the id generator for a domain class as assigned. In that case the id has to be assigned by the user.
This is a way to inform hibernate that whether you want to insert a record or just want to update.
class FoofBar{
String bar
static mapping = {
id generator: 'assigned'
}
}
def fooBar = new FooBar(bar: 'foo')
fooBar.id = 100
fooBar.save() //inserts a record with id = 100
def secondFooBar = FooBar.get(100)
secondFooBar.id = 200
//want to insert as a new row instead of updating the old one.
//This forces hibernate to use the new assigned id
fooBar.save(insert: true)
This will make it clear.

Related

Persist Grails Domains *ONLY* after Relationship built

I'm wondering if its possible to create a grails domain object, but only have it persist on command as opposed as when we do operations on it.
To be more precise, this is what I have to do now:
Foo foo = new Foo(name:"asdf")
Bar bar = new Bar(name:"gzxj")
bar.save() // persist here
foo.save() // persist here
foo.addToBars(bar) // now I have to build the relationship
What I want:
Foo foo = new Foo(name:"asdf")
Bar bar = new Bar(name:"gzxj")
foo.addToBars(bar) // just build the relationship
bar.save() // would be great to ignore this step
foo.save() // can I now atomically build both objects and create the relationships?
My impressions is that the latter would be far faster if there are many relationships to associate. Am I really just wanting NoSQL here?
Depending on how you have your relationships set up, this is entirely possible. It really has nothing to do with what database you have implemented.
Parent class
class Foo {
String name
static hasMany = [bars: Bar]
}
Child class
class Bar {
String name
Foo foo //optional back reference
static belongsTo = Foo
}
Execution
Foo foo = new Foo(name: 'a')
Bar bar = new Bar(name: 'b')
foo.addToBars(bar)
foo.save()
//or even more terse
Foo foo = new Foo(name: 'c')
foo.addToBars(new Bar(name: 'd'))
foo.save()
The key is the belongsTo which defaults to a cascade of all. This can be explicitly set as well:
class Foo {
String name
static hasMany = [bars: Bar]
static mapping = {
bars cascade: 'all'
}
}

GORM where query on an embedded object

I have domain classes A and B as follows:
class A {
String prop1
String prop2
B prop3
static embedded = ['prop3']
}
class B {
String prop4
String prop5
}
When I want to query like this:
def q = A.where { prop3.prop4 == 'bla' }
def list = q.list()
I get the following exception:
Cannot get property 'javaClass' on null object. Stacktrace follows:
on the "def q = A.where ..." line.
Any clue what's the problem? I've checked this:
http://grails.1312388.n4.nabble.com/GORM-embedded-object-issue-td1379137.html
but how to "just call them directly" is not quite clear to me. Any other way of querying the embedded objects in GORM?
I finally gave up on the where query and went with the DetachedCriteria approach. Gives me the same flexibility as the where queries, but works with embedded domain objects:
def criteria = new DetachedCriteria(A).build {
eq 'prop1', 'bla2'
}
criteria = criteria.build {
eq 'prop3.prop4', 'bla'
}
def list = criteria.list()
What do you get if you do (assuming B is in src/groovy)
def q = A.where { prop3 == new B(prop4: 'bla') }
def list = q.list()
Embedded components are persisted inside the main domain class (owner) itself. It can be accessed directly using any dynamic finder as you do directly on a domain object.
The above can also be represented in dynamic finders as:
A.findAllByProp3(new B(prop4: 'bla'))

How can i set default value in grails domain class

Is there any way to set a default value to domain class property?
I have a class called PayMethod, where I want the name property to default to "Cash" and I want this default value when I create this table, is this possible using Constraints?
package abc
import util.UserUtil
import embed.AuditUser
class PayMethod {
String name = "Cash"
AuditUser audit = new AuditUser()
static embedded = ['audit']
static constraints = {
name blank: false, size: 5..30, unique: true
}
static mapping = {
table 't01i0010'
id column: 'F_ID', precision: 4, scale: 0
name column: 'F_NAME', length: 30, defaultValue: 'Cash'
version column: 'F_REVISION'
}
def authUserService
int insertIndex = 0
int updateIndex = 0
static transients = ['authUserService', 'insertIndex', 'updateIndex']
def beforeInsert = {
audit.entryUser = UserUtil.user()
audit.entryDate = new Date();
}
def beforeUpdate = {
audit.reviseUser = UserUtil.user()
audit.reviseDate = new Date();
}
def afterInsert = {
if(insertIndex == 0){
def user = audit.entryUser
def date = audit.entryDate
log.info "POST INSERT => ENTERER: ${user} ENTERED: ${date}"
}
insertIndex++
}
def afterUpdate = {
if(updateIndex == 0){
def user = audit.reviseUser
def date = audit.reviseDate
log.info "POST UPDATE => REVISE: ${user} REVISED: ${date}"
}
updateIndex++
}
}
This will be possible in 2.2 which should be released this week or next. See http://jira.grails.org/browse/GRAILS-5520 for the relevant feature request. The syntax will be
static mapping = {
name defaultValue: "'Cash'"
}
For now you'll need to do what you're doing - set the value as the default value of the field. You can manually update the database schema, or do the work as part of a migration.
To build on the previous answer, you can use the defaultValue attribute in Grails 2.2 but you need to be careful to put double and single quotes around default values for String properties and double quotes around integer properties so that the default values appear correctly in the DDL. So, for instance, you need to use:
static mapping = {
myStringProperty defaultValue: "'Cash'"
myIntProperty defaultValue: "0"
}
If you only use single quotes, you will end up with an error like "Column "CASH" not found"
Also, as far as I can tell, default values do not work for properties that are enums.
Had the same issue and using static mapping didn't work for me either (using 2.2.3); the below link provided me a functional answer (set the default value in your object declarations):
http://grails.1312388.n4.nabble.com/How-to-set-a-default-value-for-column-td1383753.html
For String, encapsulate with quotes; int/integer should just be the value.
Hope this helps!

grails composite key update

I have a legacy database and I'm using Grails. Mistake #1.
It uses compound keys. Mistake #2.
Given these domain classes:
Movie {
static hasMany = [ roles: Role ]
}
Person {
static hasMany = [ roles: Role ]
}
Role {
Movie movie
Person person
String foo
}
I want to move roles from one person to another, like so:
Role x = person1.roles[0]
x.person = person2
save(flush:true)
But nothing happens. At all. I've turned on trace and debug level logging for hibernate in log4j and it shows no update statement. But, if I do this:
Role x = person1.roles[0]
x.person = person2
x.foo = "i can haz update?"
save(flush:true)
An update does happen for foo, but the foreign key pointing to person is not modified, as shown by:
DEBUG hibernate.SQL - update ct_roles set foo=? where movie_id=? and person_id=?
TRACE sql.BasicBinder - binding parameter [1] as 'i can haz update?'
TRACE sql.BasicBinder - binding parameter [2] as [BIGINT] - 999
TRACE sql.BasicBinder - binding parameter [3] as [BIGINT] - 2
Note that person_id 2 belongs to person2, which as yet, has no roles, so the update fails.
So, short of simply deleting the old role and creating a new one attached to the desired person, is there any way to solve this?
Try:
person1.removeFromRoles(role) //role is the role object from which person is to be removed
role.person = person2
Should work.
The answer is:
class Role {
Movie movie
Person person
String fuGorm
def move(Person newbie) {
def m = this.movie?.id
def p = this.person?.id
def n = newbie?.id
// bypass GORM and issue a raw SQL update command...
def q = "update ct_roles set person_id=$n where person_id=$p and movie_id=$m"
def success = runCommand(q)
if (success) {
// the above bypasses GORM, so we should still
// perform the operation using GORM speak
// otherwise our objects will be out of sync with the DB.
// The following EPIC FAILS to update the DB,
// but it does update the local Grails domain objects
this.person.removeFromRoles(this)
this.person = newbie
newbie.addToRoles(this)
}
return success
}
def runCommand = { query ->
def db = new Sql(dataSource)
db.execute (query)
}
}

where is bidirectional ? grails one-to-one, testing bidirectional (continue)

class Book {
String title
Date releaseDate
String ISBN
static belongsTo = [person:Person] // it makes relationship bi-directional regarding the grails-docs
}
class Person {
Book book; // it will create person.book_id
String name
Integer age
Date lastVisit
static constraints = {
book unique: true // "one-to-one". Without that = "Many-to-one".
}
}
There is a test which test if it is real bidirectional or not. As i understand it.
public void testBidirectional() {
def person = new Person(name:"person_c1", age: 99, lastVisit: new Date())
def book = new Book(
title:"somebook_c1",
ISBN: "somebook_c1",
releaseDate: new Date()
)
person.setBook (book)
assertNotNull(person.save())
def bookId = person.getBook().id
Book thatBook = Book.get(bookId)
assertNotNull(thatBook.person) // NULL !!!
}
So, i save a person with a book, and then i got that book from db by id. Then from that book i try to get back the person which book should refer to (because it should be bidirectional, right?). Eventually i got null instead of an instance of the person.
The questing is: how to make that test working?
i have found the solution how to get it working, but still can not understand why it does not work without 'refresh', see below:
public void testBidirectional() {
def person = new Person(name:"person_c1", age: 99, lastVisit: new Date())
def book = new Book(
title:"somebook_c1",
ISBN: "somebook_c1",
releaseDate: new Date()
)
person.setBook (book)
def p = person.save()
assertNotNull p
person.refresh() //load the object again from the database so all the changes made to object will be reverted
//person = Person.get(p.id) // BUT this also gets the object from db ...?
def bookId = person.getBook().id
assertNotNull bookId
def thatBook = Book.get(bookId)
assertNotNull(thatBook.person)
}
So, here as you can see i use 'refresh' to get it working, but why it does not work without 'refresh' but with the following line after 'refresh' - this one:
person = Person.get(p.id) // BUT this also gets the object from db ...?
If i just want to get object from database by id, then it would be without bidirectional?
Your problem is probably caused by the way that Hibernate works. Grails used Hibernate under the hood.
Even when you call "save", the object person may (and usually) not saved in database. That's because Hibernate is programmed to optimize the query, so it often waits to perform all query at then end of the Hibernate session.
That means if you don't call "refresh", the book-person relation (person.setBook) is still in memory, but not saved in database. Hence you can't get the book.person from book.
To enforce the save, you can use "refresh" like the previous answer, or use flush:true.
I still not try, but it's very likely that you will produce desired results with:
person.save(flush:true)

Resources