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.
Related
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.
I have a parent table Parent and a child table Child. The relation is like this:
class Parent {
...
Child child
static mapping = {
child lazy: false, cascade: 'all'
}
static constraints = { ... }
}
class Child {
String name
static constraints = {
name unique: true
}
}
I created some code to add a child to an existing parent. It looks like this:
def parent = Parent.get(id)
parent.child = new Child(name: (name))
parent.save()
This code is contained in a method of transactional service.
It does not work when child is invalid - no validation happens. I get a famous hibernate error:
object references an unsaved transient instance - save the transient instance
before flushing`.
It can be easily explained: child is not validated, when GORM saves objects, it tries to save child, then it should stop due to a failure, but it proceeds and tries to save parent with unsaved child field.
How can I work around the case when child is invalid? I need to propagate information about the error to a view form.
I've already tried to validate child manually - it's errors field contains 1 error, but parent is still valid. I've tried to insert the error to the parent errors field - parent becomes invalid, but GORM still tries to save it.
Do you have belongsTo defined (e.g static belongsTo = [Parent]) in your relationship between Child and Parent? If you do not, Grails will not cascade the save/update from the Parent to the Child since it doesn't "own" the Child - thus if no save is happening on the Child, then validation never gets called. So try adding
static belongsTo = [Parent]
in the Child class and saving again, possibly with deepValidate:true as well if you're still not seeing the Child validation occurring.
Thanks for this nice Answer i was facing same problem due to your post i resolve the problem
def val = (params.company).toInteger()
def parent = Company.get(val)
.addToJobs(new Job(
experience:params.months,
jobdescription:params.desc,
joblocation:params.companyloc,
jobskills:params.skills,
jobtype:params.emp,
salary:params.jobsalary,
jobtitle:params.jobtitle))
.save()
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)"
}
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.
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