How to remove object from database in test in Grails - grails

I have got a domain:
MyClass
with fields
String a
String b
I got a test:
void testRemoveMyClass() {
MyClass x = new MyClass()
x.setId(3)
x.setA("AAA")
x.setB("BBB")
x.save()
if (!MyClass.exists(3)) {
fail "Object does not exist"
}
x.delete()
if (MyClass.exists(3)) {
fail "Object exists"
}
}
And the second 'fail' fails. How can I delete this object by Id?

First of all: do NOT use typed references, use:
def x = new MyClass()
Very good reading about his topic: http://blog.springsource.org/2010/07/28/gorm-gotchas-part-3/
Your object still exists, but it should not be persisted anymore. Try by the end of the test, instead of the second exists():
def y = MyClass.findById(3)
assert y == null
BTW, you can create your domain objects eaisier via map in constructor:
def x = new MyClass(id: 3, a: 'AAA', b: 'BBB')

Related

Groovy: Dynamic nested properties [duplicate]

I am wondering if I can pass variable to be evaluated as String inside gstring evaluation.
simplest example will be some thing like
def var ='person.lName'
def value = "${var}"
println(value)
I am looking to get output the value of lastName in the person instance. As a last resort I can use reflection, but wondering there should be some thing simpler in groovy, that I am not aware of.
Can you try:
def var = Eval.me( 'new Date()' )
In place of the first line in your example.
The Eval class is documented here
edit
I am guessing (from your updated question) that you have a person variable, and then people are passing in a String like person.lName , and you want to return the lName property of that class?
Can you try something like this using GroovyShell?
// Assuming we have a Person class
class Person {
String fName
String lName
}
// And a variable 'person' stored in the binding of the script
person = new Person( fName:'tim', lName:'yates' )
// And given a command string to execute
def commandString = 'person.lName'
GroovyShell shell = new GroovyShell( binding )
def result = shell.evaluate( commandString )
Or this, using direct string parsing and property access
// Assuming we have a Person class
class Person {
String fName
String lName
}
// And a variable 'person' stored in the binding of the script
person = new Person( fName:'tim', lName:'yates' )
// And given a command string to execute
def commandString = 'person.lName'
// Split the command string into a list based on '.', and inject starting with null
def result = commandString.split( /\./ ).inject( null ) { curr, prop ->
// if curr is null, then return the property from the binding
// Otherwise try to get the given property from the curr object
curr?."$prop" ?: binding[ prop ]
}

Grails fails to delete orphan on collection in Unit tests, if composite id is used

I am using Grails 2.4.4. I would like to test
the persistence in Unit Test Class with an in-memory database.
I have a Parent class with a oneToMany relation with Child. The Child is ownedBy the Parent and has a composite key involving the parent. When I try to delete one of the Children in the collection inside Parent, I get an error if I flush, no delete is fired if I omit the 'flush: true' parameter.
class Parent implements Serializable {
String name
static hasMany = [children : Child]
static mapping = {
children cascade: 'all-delete-orphan'
}
}
class OtherParent implements Serializable {
String name
}
class Child implements Serializable {
String name
static belongsTo = [ owner : Parent, secondOwner : OtherParent]
static mapping = {
id composite : ['owner', 'secondOwner']
}
}
I would like to test relations in unit test classes annotated like this
#Domain([Parent, OtherParent, Child])
#TestMixin(HibernateTestMixin)
class ChildSpec extends Specification {
def "Parents and Children can be created, saved and deleted"() {
given: "we have a clean database at the start"
Parent.count() == 0
OtherParent.count() == 0
Child.count() == 0
and:
Parent a = new Parent()
a.name = "Parent"
OtherParent secondParent = new OtherParent ()
secondParent.name = 'Second Parent'
Child b = new Child()
b.name = "Child"
b.otherOwner = secondParent
a.addToChildren(b)
when: "we save Parent"
secondParent.save(flush: true, failOnError: true)
a.save(flush: true, failOnError: true)
then: "Parent saves and Child is saved too"
Parent.count() == 1
Child.count() == 1
def savedA = Parent.findByName("Parent")
savedA.name == "Parent"
savedA.children.size() == 1
def savedB = savedA.children.getAt(0)
savedB.name == "Child"
def foundB = Child.findByName("Child")
foundB.name == "Child"
when: "we remove Child from Parent, we can still save Parent"
savedA.removeFromChildren(savedB)
savedB.delete(flush: true)
savedA.save(failOnError: true, flush: true)
then: "we've got an Parent with no Bs and no exception is thrown"
notThrown(Exception)
Child.count() == 0
}
}
But an Exception is thrown
Expected no exception of type 'java.lang.Exception' to be thrown, but got it nevertheless
at spock.lang.Specification.notThrown(Specification.java:106)
at eu.europa.ec.comp.redda.test.ParentSpec.Parents and Chilren can be created, saved and deleted(ParentSpec.groovy:56)
Caused by: org.springframework.orm.hibernate4.HibernateOptimisticLockingFailureException: Object of class [eu.europa.ec.comp.redda.test.Child] with identifier [eu.europa.ec.comp.redda.test.Child : (unsaved)]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [eu.europa.ec.comp.redda.test.Child#eu.europa.ec.comp.redda.test.Child : (unsaved)]
at org.springframework.orm.hibernate4.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:200)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate.convertHibernateAccessException(GrailsHibernateTemplate.java:593)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate.doExecute(GrailsHibernateTemplate.java:183)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate.execute(GrailsHibernateTemplate.java:123)
at org.codehaus.groovy.grails.orm.hibernate.InstanceApiHelper.delete(InstanceApiHelper.java:36)
at org.codehaus.groovy.grails.orm.hibernate.HibernateGormInstanceApi.delete(HibernateGormInstanceApi.groovy:228)
at eu.europa.ec.comp.redda.test.ParentSpec.Parents and Chilren can be created, saved and deleted(ParentSpec.groovy:52)
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [eu.europa.ec.comp.redda.test.Child#eu.europa.ec.comp.redda.test.Child : (unsaved)]
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:2541)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3403)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3630)
at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:114)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:463)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:349)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1222)
at org.codehaus.groovy.grails.orm.hibernate.InstanceApiHelper$1.doInHibernate(InstanceApiHelper.java:40)
at org.codehaus.groovy.grails.orm.hibernate.InstanceApiHelper$1.doInHibernate(InstanceApiHelper.java:36)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate.doExecute(GrailsHibernateTemplate.java:179)
... 4 more
Your unit test needs some data to be set up for your test. If you want to test that you can create and save your objects, then try this (you're also missing a name property for the A domain class, and let's also assume there's one for the B class too):
def "As and Bs can be created, saved and deleted"() {
expect: "we have a clean database at the start"
A.count() == 0
B.count() == 0
given:
A a = new A()
a.name = "A"
B b = new B()
b.name = "B"
a.addToBs(b)
when: "we save A"
a.save(flush: true, failOnError: true)
then: "A saves and B is saved too"
A.count() == 1
B.count() == 1
def savedA = A.findByName("A")
savedA.name == "A"
savedA.bs.size() == 1
def savedB = savedA.bs.getAt(0)
savedB.name == "B"
def foundB = B.findByName("B")
foundB.name == "B"
when: "we remove B from A, we can still save A"
savedA.removeFromBs(savedB)
savedB.delete(flush: true)
savedA.save(flush: true)
then: "we've got an A with no Bs and no exception is thrown"
notThrown(Exception)
savedA.bs.count() == 0
}
EDIT to reflect change to the question:
Your domain model means that a Child must belong to both a Parent and an OtherParent; it is not an either/or relationship. Are you sure this is what you want?
If it is what you want, I still don't understand why you want a composite id? Also, you haven't included OtherParent in the #Domain annotation. The code here will work if you remove the composite id mapping.

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'))

Benefits of using Insert flag in Grails save()

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.

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)
}
}

Resources