Grails finding parent by the many side - grails

My problem should be obvious, but I just don't see the light right now :-(
I have two domainclasses like this:
class Parent {
String name
static hasMany = [children: Child]
}
class Child {
String name
}
Now I should be able to find the Parent of a child by using the dynamic finder of the Parent like:
Parent.findByChildren([someChild] as Set)
But I get a hibernate error stating that I've got a grammar error in my hibernate SQL:
Caused by: java.sql.SQLException: No value specified for parameter 1
And for the reference: someChild IS a concrete instance. And I would like to avoid Child to have an explicit parent in the definition.
How then can I go from the Child to the Parent?
Best Regards,
Christian Sonne Jensen

Just to end this question, I wanted to report a solution to my "problem". I'm using a namedQuery in the Parent entity (Customer or Producer) like this:
Class Customer {
static hasMany = [channels: Channel]
static namedQueries = {
findByChannel {
channelId ->
channels {
eq 'id', channelId
}
}
}
}
Then I find the Customer like this:
def customers = Customer.findByChannel(channel.id).list()
In this way the Channel are relieved of the burden of knowing anything about who references it, and I don't have to do any artificial relationship tables.
I still think that it must be some kind of mistake that I cannot use one of the dynamic finders:
Customer.findByChannels([channel] as Set)
Maybe the dynamic finders doesn't take one-to-many relationsships into account, and only works for simple attributes??? (I'm using Grails 1.3.1)
Thanks for your replies though!
Christian Sonne Jensen

If you don't want the parent foreign key on the child, you'll have to create a join table for the parent that serves as a surrogate for the child:
class ParentalRelationship {
static belongsTo = [parent: Parent, child: Child]
}
You could then have helper methods on the parent to query for children through the ParentalRelationship object.
With your real implementation of Customers, Channels, and Producers, chances are that you'd want a many-to-many relationship anyways as a channel wouldn't belong to a single customer (or a single producer).

Maybe a better way is to write in the chield the belongsTo something like this:
static belongsTo = [parent: Parent]
And then you can use:
Chield c = ...
Parent parent = c.parent

I would invert it:
class Parent {
String name
static Set<Child> getChildren() {
Child.findAllByParent(this) as Set
}
}
class Child {
String name
Parent parent
}
This uses the same database structure (the child table has a foreign key to parent) but makes it easy to go from one side to the other without being explicitly bidirectional.
One thing does change. Instead of this:
def parent = ...
parent.addToChildren(new Child(...))
parent.save()
you do this:
def parent = ...
def child = new Child(parent: parent, ...).save()
This is more performant because you don't need to load the entire collection just to persist a new child.

Related

Find subdomain using domain instances in Grails

In grails, how do I find subdomain using domain instances
Let say I have
class Family {
Integer id
Parent parent
}
class Parent {
Interger id
static hasMany = [children: Child]
}
class Child {
String name
}
So in controller,
Parent mom = Family.findById(1).parent
so now, how do I use mom to get a child with name == "Child" in parent?
Is it even possible?
I think this should work.
Child child = mom.children.find { it.name == 'child' }
But I do not recommend using this kind of queries. Grails has many ways for querying you can read about it here http://gorm.grails.org/latest/hibernate/manual/index.html#querying. I also recommend to you this guide http://guides.grails.org/querying-gorm-dynamic-finders/guide/index.html its about dynamic finders in contrast to queries that use groovy collection methods for querying.
I hope its help full
You can use the criteria API for that:
Parent.withCriteria {
children {
eq("name", "Bob")
}
}
In this example children will be joined to the parent. And all parents will be returned, that have a child called "Bob".
You can simply use closure findAll{} this way:
def childrenList=mom.findAll{it.children.each{
if(it.name=='child')
return it
}
}
This will give you a list of all the children objects with name 'Child'.
As #user615274 has suggested, the accepted solution works but that it may have performance issues.
One feature that Grails shine is the dynamic query. I would modify the Child domain and use dynamic query. eg.
Since Parent "hasMany" relation to Child, the child "belongsTo" the Parent
class Child {
String name
Parent parent
// or static belongsTo = [parent:Parent]
}
Once this relationship is setup, then you can use dynamic query
def child = Child.findByParent(mom) // return the first matching result
def children = Child.findAllByParent(mom) // returns a list of matching result
I hope this helps.

Unidirectional Many To One mapping with cascade

Is it possible to map the following with GORM?
I want to get rid off all associated events when I delete a person.
Person object should not have a link to events.( I want to avoid using hasMany on Person domain)
class Person {
String username
}
class Event {
String description
static belongsTo = [person:Person]
}
I'm getting now a 'Referential integrity constraint violation' when doing person.delete() because events are not removed before deleting person.
I don't think that is possible without using hasMany (speaking of which, why do you want to avoid that anyway?)
This SO Question states:
Hibernate only cascades along the defined associations. If A knows
nothing about Bs, nothing you do with A will affect Bs.
Use static hasMany and bam, problem fixed.
Edit:
The only way I think you could achieve this is using beforeDelete on the Person class to delete all the associated Events, i.e.
class Person {
def beforeDelete() {
def events = Event.findAllByPerson(this)
for (e in events) {
e.delete()
}
}
}
See the documentation on Events and Auto Timestamping for more info on that.
The above will not work
Why not define a no reference mapping:
class Person {
String username
static hasMany=[Events]
}
This way there is no actual bindings of events to person but a person can have many events

Gorm not doing join

I'm trying to build a hierarchy of a class I've called group. The domain is fairly simple:
class SubGroup implements Serializable {
Group child
Group parent
static mapping = {
id composite: ['child', 'parent']
}
}
class Group implements Serializable {
int groupId
String key
String title
static mapping = {
id name: 'groupId'
}
}
Basically I'd like to build up a map of group parents and their associated children. So I'm looping through each record (if there's a cleaner way to query for a Map I'm happy to hear it) and creating the map entry for it.
Map hierarchy = [:]
SubGroup.list().each { relation ->
if (!hierarchy[relation.parent]) {
hierarchy[relation.parent] = new HashSet()
}
hierarchy[relation.parent] << relation.child
}
I would think hibernate would use some simple query that does this something like this:
select * from sub_group s, group c, group p
where s.child_id = c.group_id and s.parent_id = p.group_id
But it is not doing the join. It is doing a query of the subgroup followed by n queries of the group table (N+1 select problem). Ugh. I heard in 2.0 there's a problem with the hibernate query cache so I disabled it. I've tried adding lazy: false, and fetch: join to my SubGroup domain class for both the parent and the child columns with no luck. I've tried adding (fetch: [child: 'eager']) as a parameter to the list method. It will not do the join. Am I missing something? To be honest, it shouldn't really even need to do a join as I am only accessing the groupId foreign key property although later on I will need both the key and title properties.
I could, of course, make the child and parent properties ints and just do my own querying when I need the rest of the data or I could use HQL and some other method for limiting this to a single query, but it seems like GORM should be doing this for me. Thanks for your help.
Regards,
Jim
It seems the only way I could get this to work without hibernate making a select call for each child and parent was to instead do a HQL query rather than using the list method as shown below:
Map hierarchy = [:]
def subGroups = SubGroup.executeQuery("SELECT s.parent, s.child FROM SubGroup s")
subGroups.each { relation ->
if (!hierarchy[relation[0]]) {
hierarchy[relation[0]] = new HashSet()
}
hierarchy[relation[0]] << relation[1]
}
Thus I'm really only using the SubGroup domain class to define the relationships. I would think I should be able to do this via some kind of mapping but I couldn't figure out how.

Grails hasMany: when child is updated, parent's version changes

I am using Grails and am quite surprised by the way hasMany relationships work. I have a typical hasMany relationship where the parent id is in the child table. When I insert a child and try to save it through the parent object, the parent object's version id gets incremented. My question is: Why should the parent's version id change when there is a change only in the child object?
class Parent {
static hasMany = [children: child]
}
class child {
string name
Parent parent
static belongsTo = [Parent]
}
def p = Parent.get(1)
p.addToChildren(new Child(name: "Roy"))
p.save()
The version of p gets incremented from 0 to 1. Is there any way I can avoid this in Grails?
Due to the change in version ID of the parent I get a stale object exception. Any help?
One possibility is to disable optimistic locking for your domain object.
Update
Or try to search.

Grails domain class relationship to itself

I need a way to be able to have a domain class to have many of itself. In other words, there is a parent and child relationship. The table I'm working on has data and then a column called "parent_id". If any item has the parent_id set, it is a child of that element.
Is there any way in Grails to tell hasMany which field to look at for a reference?
This is an example of what you are looking for (it's a snippet code I am running and it generates column parent_id). I don't think you need SortedSet:
class NavMenu implements Comparable {
String category
int rank = 0
String title
Boolean active = false
//NavMenu parent
SortedSet subItems
static hasMany = [subItems: NavMenu]
static belongsTo = [parent: NavMenu]
}
Furthermore, you can give name to the hasMany clause using the Mapping DSL, which is explained at http://grails.org/GORM+-+Mapping+DSL

Resources