Grails Domain Object hasMany irregular behaviour using contains - grails

I'm having an issue where calling .contains() on one of my domain classes' hasMany relationships is not doing the same when running normally, or when debugging. The situation is as follows:
I have 2 domain objects, A and B. A has a hasMany relationship with B.
class A {
...
static hasMany = [bees: B]
...
}
Now, during the execution of one of my filters, I grab my current user from the spring security service. This user also contains a single instance of B. What my filter should do is to check if the instance of B in the user is contained in some instance of A.
Assume that the instances of B are actually referring to the same object (since they are).
Now, the issue arises. Calling:
if (instanceOfA.bees.contains(user.instanceOfB)) {
println 'success'
} else {
println 'failure'
}
prints failure during normal (or debugging without stepping through the code) execution. However, if I put a break-point there, and step through the code, it correctly executes the contains() and prints success.
I have also implemented equals, hashCode and compareTo in an attempt to resolve this, but with the same behaviour.

This is usually due to lazyloading or cache. Use instanceOfA.bees.id.contains(user.instanceOfB.id) and it always works.

Maybe your user.instanceOfB object is a hibernate proxy object and therefore not a real B. You can check this using a debugger or printing user.instanceOfB.getClass().
You can use GrailsHibernateUtil.unwrapIfProxy(proxyObject) to get the real object from the proxy.

I would do this with HQL:
A.executeQuery("select a from A a join a.bees as b where b = :b and a = :a", [a: instanceOfA, b: user.instanceOfB])

So it seems that using one of the Groovy transform annotations seems to do the trick. Simply adding:
// uid is a uniqe UUID we use to identify with other systems.
#EqualsAndHashCode(includes = ["id", "uid"])
does the trick. Seems a bit strange that the IDE generated methods (using the same fields) did not...

Related

Grails 2.4.4 upgrade data binding issue

A pattern we use here for large dynamic forms is to allow the client to edit pretty much the entire graph including children and removal and addition of children is handled in javascript. Failing use case is when user deletes a property of one of the children and for this example we'll say the email address of the second child is removed and the parm is sent empty.
Example Class Structure
Domain X
Long id
String name
SortedSet<Child> children
Domain Child
Long id
Integer position // used to sort
String name (required)
String email (required)
Parms are named in this manner:
x.id = 1
x.name = 'blah'
x.children[0].id = 1
x.children[0].position = 0
x.children[0].name = 'childa0'
x.children[0].email = 'child0#any.com'
x.children[1].id = 2
x.children[1].position = 1
x.children[1].name = 'child1'
x.children[1].email = ''
Current stored values:
x.id = 1
x.name = 'blah'
x.children[0].id = 1
x.children[0].position = 0
x.children[0].name = 'childa0'
x.children[0].email = 'child0#any.com'
x.children[1].id = 2
x.children[1].position = 1
x.children[1].name = 'child1'
x.children[1].email = 'child1#any.com'
The pattern to update has been:
Browser
user edits all and submits changes
parms are sent as shown above and in this use case user accidentally deleted email address that is required (yes submit could be prevented in this simple case but there are more extensive validation rules and this is just a simple example to illustrate issue)
Server
retrieve current parent domain class using id parm
check current stored version against edited version and ensure it has not changed
apply all parms to current domain object in this manner: x.properties = parms.x
This is where it breaks down. With Grails 2.2.2 the email property of child[1] is updated to an empty string and running validation catches the error. Grails 2.4.4 does NOT update the child value. I know the data binding changed and perhaps there are valid reasons for this change but I can't fathom it. This has worked from 1.3.6 to 2.2.2.
One thing to note is that if I do not retrieve the domain class and instead create a new instance with the parms passed in all of the child parms are set correctly.
X x = new X(params.x)
This seems to indicate some Grails issue as the user guide talks about both methods as equal - one to use for new instances and the other for updates but the examples clearly demonstrate that both methods should handle indexed child properties.
Any help or thoughts are appreciated!
I ran into this problem my self upgrading an application from 2.2.4 to 2.4.4.
Setting grails.databinding.useSpringBinder = true for config.groovy
and adding grails-web-databinding-spring to the pom worked flawlessy for me.
Obviously doing this was a lot less hassle than rewriting all the binding code :-)
Looking into this further Grails 2.4.4 documentation states that it will bind sets positionally if they are indexed (ie. [0]).
http://grails.org/doc/latest/guide/single.html#dataBinding
The section titled "Data Binding and Many-ended Associations" states that these parms will be bound and that new instances of the set will be created if their index is greater than the current set. This was true for me in Grails 2.2.2 but NOT in 2.4.4.
HOWEVER, earlier in the documentation in the section "Binding To Collections And Maps" it states clearly: "When updating existing elements in a Set the Map being assigned to the Set must have id elements in it which represent the element in the Set".
If you are upgrading to Grails 2.4.4 and have any complex form data binding I suggest you look there first to decide whether to upgrade. Due to these changes in data binding this has become the most complex upgrade we've encountered yet with Grails.
The other disappointment with 2.4.4 is that it states you can override the new binding and fall back to the old spring binding but you cannot past 2.4 - at least from what I can gather from others' posts and my attempts. Setting the config property as documented and adding the dependency required resulted in startup runtime errors.
Apparently older versions of grails prior to 2.4.4 would match the child instances to params positionally, i.e. using the indexes ([0],[1], etc.) to match the children not caring if the IDs of the instances matched. The new binder does want the IDs of the instances to match before binding. I had never realised I was not placing the ID in a hidden field as it always worked perfectly.
I had a similar problem after migrating to Grails 2.4.4 (from 2.2.2). After a lot of reading and seaching (you must to definitly read http://docs.grails.org/2.4.4/guide/single.html#dataBinding mencioned in user2863513 post) I've resolved it in a very simple way
In my application I had nested domains relationships. Example:
class A {
String name
static hasMany = [b:B]
}
class B {
String name
static hasMany = [c:C]
}
class C {
String name
}
Due to the form complexity, class C object were not binding correcly. I've resolved this defining the C atribute on class B as a List (remember, has many relationships are implemented as Sets by default). So, my class B changed to:
class B {
String name
static hasMany = [c:C]
List c
}
And voila! Everything works perfectly again.

How to load any attributes without using the Mapping ' lazy: false' in Grails

Constantly faced with a problem when I need to compare and manipulate objects that reference other objects. For example:
Class Student {
...
String Name
Integer Age
...
}
Class Stuff {
...
Student student
...
}
When I invoke an instance of Stuff (Stuff.get (id)/load(id)) and will access the Name, Age and other attribute I see in debug mode (stuff .name = null, they're like 'null' although they are not null. It
command when analyzing values ​​of these attributes (stuff
.name == "pen") error occurs.
I need to invoke the instances and compare their values ​​to execute business rules, but do not know how to resolve this issue.
I read something about the inclusion in the configuration Stuff Mapping 'student lazy: false' for all the time you need to load the instance ofstuff , also charge the Student, but that in addition to overload the memory (since stuff is a Domain Great) would solve this case being the only solution to put all references as 'lazy: false' which would slow the application just to make a simple comparison.
Does anyone know how to invoke instances (Stuff), automatically invoking the attribute to be working (student) just to make the comparison of data, without using the 'student lazy: false' that invokes the data at all times?...
Using Grails 2.2.0 e o Groovy 2
Stuff don't have a property called name so you should get MissingPropertyException calling stuff.name. This has nothing to do with the lazy or eager relationship.
You can check the definition of a lazy relationship in the documentation and also the difference between the types of fetch.
To access the name property you need to access the student property before:
Stuff instance = Stuff.get(id)
println instance.student.name //this, if lazy, will trigger a new database query.
If you know that your code will access the Student instance by the relation with Stuff you could fetch both in one database access (eager and not lazy):
Stuff instance = Stuff.withCriteria {
eq('id', id)
fetchMode("student", FetchMode.JOIN)
}

Grails searchable returns domain but relation is null

I have 3 domains: A, B, C.
A and C have many-to-many relationship through B.
A and C are searchable.
When I search and get list of A domain all the fields in A are accessible, however relation field is always 'null'. Why I can't access relational field? Why do I get 'null'? If I access object directly, I see a relation, but when searchable returns A domain, I get 'null' on a relation field.
P.S: I tried to make B searchable but it looks like searchable having issue with indexing it on top of that I don't see any point in indexing B since it exists for the sake of many-to-many relationship only.
Please I need help with it. I need to be able to get to C via A on a searchable return.
Thank you.
[Update]: I made a prototype project today (small DB) and made domain B searchable. Now I can access relational field. However in my real project, I don't want to make B searchable since database is big and indexing takes too long. Is there a way around it?
You can refrash all instance in result list or use reload:true property for seach method
searchableService.search(query,[reload:true])
You can find full list of options: http://grails.org/Searchable+Plugin+-+Methods+-+search
reload - If true, reloads the objects from the database, attaching them to a Hibernate session, otherwise the objects are reconstructed from the index. Default is false
Ok, I believe I solved my issue.
First checkout link to a similar question: Grails searchable plugin -- Please give GalmWing some credit.
My solution is following, I am implementing my own controller and following piece of code implements searchable service call:
if (params.q) {
try{
def searchResults = searchableService.search(params.q, params)
searchResults.results.each {
it.refresh()
}
return [carInstanceList:searchResults.results, carInstanceTotal:searchResults.total]
} catch (SearchEngineQueryParseException ex) {
return [parseException: true]
}
As you can see I have a loop where on each item of domain "A" I do refresh. Now refresh gets real record from DB with all the links. Now I return list into GSP and it extracts all of "C" domains associated with the "A" domain.
Now this way you might get performance penalty, but in my case searchable is actually not able to index "B" domain, it is working for a while and then crashes, so I don't have another choice, at least for now.

Lazy fetching of objects using FindAllBy , for the first time

When I use criteria queries, the result contains array list of lazy initialized objects. that is, the list has values with handler org.codehaus.groovy.grails.orm.hibernate.proxy.GroovyAwareJavassistLazyInitializer.
This prevent me from doing any array operation (minus, remove etc) in it. When I use, GORM methods, I get array list of actual object types. How can I get the actual objects in criteria query?
The code is listed below.
availableTypes = Type.withCriteria() {
'in'("roleFrom", from)
'in'("roleTo", to)
}
availableTypes (an array list) has one value , but not actual object but value with a handler of GroovyAwareJavassistLazyInitializer
availableTypes (an array list) has values with type Type
availableTypes = Type.findByRoleFrom(from)
---------- Update ----------
I did further troubleshooting, and this is what I found. Probably the above description might be misleading, but I kept it in case it helps.
When using findAllBy for the first time, I get proxy objects rather than the actual instance. Then, I invoke the method through an ajax call, the actual instance is loaded (anything to do with cache loading??). When I refresh the page, it again loads the proxy
def typeFrom = Type.findAllByParty(partyFrom)
there is another use of findAllBy in the same method, which always returns actual instances.
def relFrom = Relation.findAllByParty(partyFrom)
When compared the two classes, the attribute 'party' of class Roles is part of a 1-m relation. like
class Role {
RoleType roleType
LocalDate validFrom
LocalDate validTo
static belongsTo = [party : Party ]
...
}
I know if I do statement like Party.findAll(), the role instances would be proxy till they access. But, when using gorm directly on the class (Role), why I am getting the proxy objects ???
thanks for the help.
thanks.
Turns out are a couple of possible solutions which I came across but didn't try, such as
Overloading the equals method so that the proxy and the domain
object use a primary key instead of the hashCode for equality
Using a join query so that you get actual instances back and not proxies
GrailsHibernateUtil.unwrapProxy(o)
HibernateProxyHelper.getClassWithoutInitializingProxy(object)
One solution that worked for me was to specify lazy loading to be false in the domain object mapping.
History of this problem seems to be discussed here: GRAILS-4614
See also: eager load

Grails : data binding

i'm trying to create some domain objects from xml.
class A {
String name
}
class B {
A a
int something
}
i first created an instance of A,and flushed. when creating B, first map the available attributes.
def b = new B(xml.attributes())
this would map 'something' correctly, but not the object type A. So, I retrieve the instance of A and add like
b.a = A.findByA("id of a")
I could see the object b is constructed (both fields filled in) in the debugger, but it doesn't persist on save(flush:true).
What is wrong in the above assignemt, or should use the id instead (b.a.id = ..)
How can I see what is going wrong in the log file? which trace needs to be enabled. I enabled there in config file
trace 'org.hibernate.SQL', 'org.hibernate.type' (which gives the sql trace for insert, select etc. But not for the above scenario, may be because it doesn't reach to hibernate).
Any pointer, highly appreciated.. thanks.
I would wager to guess that your save() is failing validation. You can add save(failOnError:true) to throw an exception when the validation fails, or add the following code to print each of the errors:
b.errors.allErrors.each {
println it
}
With the debugging tip from Rich, I could narrow down the problem... had to rename the attribute to prevent auto mapping. See a similar issue, and response at http://grails.1312388.n4.nabble.com/domain-controller-and-Failed-to-convert-property-value-of-type-problem-td1357947.html
To create association you must pass an object of A
new B(a:A.get(id))
or
B b = new B()
b.a = A.get(id)
Where id must be Integer or Long
Either I miss some context but class A doesn't have method findByA. There is no such A attribute for class A. Suggest you to use method get for strict findings.

Resources