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.
Related
I'm using the following criteria to retrieve all Person objects that have certain roles granted (in the PersonService):
#Transactional(readOnly = true)
List findAllByRoles(authorities) {
Person.createCriteria().list {
personRoles {
role {
'in'('authority', authorities)
}
}
order('name', 'asc')
}.unique(false)
}
I now have the problem that it returns a List with Person__$$__javassist_67 objects rather than Person objects.
How could I alter the statement in order to retrieve Person objects?
EDIT:
I need this because I'm using the list I get here in connection with another list of Person objects. As I wanted to use removeAll on one of the two lists both need to contain objects of the same type what was not the case.
Implement the equals method on Person to be able to identify if 2 instances are equal, which will work across proxy
The Person__$$__javassist_67 object is just a proxy for the Person class in this instance, caused most likely by lazy fetching. I'm not sure why you are getting it in this situation. I would attempt to explicitly set the fetchMode:
import org.hibernate.FetchMode
...
Person.createCriteria().list {
fetchMode("personRoles", FetchMode.JOIN)
fetchMode("role", FetchMode.JOIN)
personRoles {
role {
'in'('authority', authorities)
}
}
order('name', 'asc')
}.unique(false)
You may not need the second fetchMode.
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.
I have a parent domain class the has a hasMany of another domain class. Both the parent and the child domain classes have the lastUpdated and the dateCreated fields. My issue is that when I update a child domain class, I need the parent domain class to reflect that change and update its lastUpdated field as well.
Is there any mapping or other configuration between the parent and child that Grails provides that would implement this feature?
Update
I added the following lines to the child domain class:
def beforeUpdate = {
parent.lastUpdated = new Date()
}
I also had to make sure in the controller that when I updated a child, I also had to save the parent as well to persist the new lastUpdated field. This seems to work fine, but I would still like to know if there is a mapping or something similar that would do this.
I have a feeling your suggested implementation will be buggy. You're updating the parent by setting the lastUpdated date manually, which might cause grails to update lastUpdated again after it does dirty checking on it. If that's the case, you would actually end up with a lastUpdated time that occurred after the date you original set. In your testing, this might be only a few (milli)seconds, but you can't guarantee that.
Not only that, but your implementation is harder to maintain since you have increased the coupling of Parent and Child.
Might I suggest another implementation? The lastUpdated field is supposed to represent the time the specific domain object was updated. The date you're looking for is not quite the same thing, so I wouldn't try to use the existing convention in the "wrong" way. It sounds like the date you want for the parent object is "the last time a child was modified".
Use a formula instead.
To do that, you could use a formula. With a formula, you get exactly what you want without having to directly modify the parent object, and you can still use dynamic finders and other Grails sugar.
class Parent {
...
Date lastChildUpdated
static hasMany = [ children: Child ]
static mapping = {
...
lastChildUpdated formula: '(SELECT max(c.last_updated) FROM child c WHERE c.parent_id = id)'
}
}
GORM will load the value of the formula in whenever you read the object from the database. Now, whenever you save a Child, the parent will have an accurate value for that property without having to touch the Parent.
I used a hack. I have added a Long updateTrigger field to my parent domain class and a touch method:
class Parent {
Long updateTrigger
static mapping = {
autoTimestamp true
}
static constraints = {
updateTrigger(nullable:true)
}
public touch() {
if (updateTrigger == null) updateTrigger = 0
updateTrigger++
this
}
In the update/save actions of the child controller, I just call:
child_instance.save() // save the child
child_instance.parent.touch().save() // updates parent's time stamp
This will increment the updateTrigger value, and the save() will automatically update the lastUpdated field thanks to the autoTimestamp set to true in the mapping. updatedTrigger is set to be nullable so that it doesn't invalidate any existing database table and therefore can be added anytime to any domain class.
In one of my project where the domain was like.
A Program has many AdvertisingMaterial and we have subclasses of AdvertisingMaterial, FlashAd, ImageAd etc. The user want the ability to filter the programs which has flashAds, imageAds etc. Now I need to do the filtering on the basis of the class property that we have in database table (When table tablePerHierarchy is true). So I did some changes in my domain class to get this property.
class AdvertisingMaterial {
String className
static constraints = {
className(nullable: true)
}
static mapping = {
className formula: 'CLASS'
}
}
Now what I can use this className field in my dynamic finders and criteria query as well. So I can do something like
List<AdvertisingMaterial>adMaterials=AdvertisingMaterial.findAllByClassName("com.project.FlashAd")
static mapping = {
fullName formula: "CONCAT(FIRST_NAME,' ',LAST_NAME)"
totalAmount formula: "SUM(AMOUNT)"
}
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.
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.