I have two domain objects A and B.
A can be associated with many Bs but I do not want any save cascade from A to B.
I'm thinking of defining the hasMany relationship form A to B, but then setting a cascade behavior. Any ideas?
This is an example of my domain objects:
class A{
static hasMany = [bees:B]
}
class B{
}
If you do not wish for GORM to manage the save/updates for your collection simply don't use hasMany. Instead treat it as a simple HashSet property.
Why not use 'belongsTo' on B, and don't declare anything on A? This way you'll get the foreign key to 'A', but operations on 'A' won't affect 'B'. You lose a bit of convenience, but can still easily look up all 'B' by 'A'. I actually prefer this because I don't need to worry about lazy loading gotchas and hibernate going and loading all the 'B's when I'm just trying to add one (assuming you don't need that functionality).
class A{}
class B{
static belongsTo = [your_a:A]
}
//get your B's for a given A
B.findAllByA(your_A_instance, ...paging, etc...)
You can define your own cascading behavior in the static mappings block of your Domain class.
See here: http://grails.org/doc/latest/ref/Database%20Mapping/cascade.html
If you are saying what I think your are saying then what you are talking about is not cascading. A simple outline of your classes would be helpful. If you have an instance of A which is associated with many instances of B, then all instance of B which reference the instance of A in question are referencing the exact same object. I had the same problem and asked a similar question here. Basically your options are:
1.) Clone the instance of A whenever it changes or whenever you deem appropriate.
2.) Create new fields in your B class which will hold the values of A you are concerned with.
Both approaches have their advantages and disadvantages, but for me option 2 proved to be the better choice.
Related
I've got a domain called Planning that has a hasMany of another domain called Employee included in it. I'm trying to do a findAll of these plannings where the plannings contain a particular employee and I can't get it to work.
I'm trying to do it like so, my print statements do print the contains as true
plannings = plannings.findAll{planning->
if(employee) {
log.info("find plannings with employee ${employee} ${planning.employees.contains(employee)}")
planning.employees.contains(employee)
}
}
I'm not doing this as a Hibernate query as this broke the application in another weird way. This code is executed in a for each and for whatever reason that causes some weird behavior with Hibernate.
The closure must return a boolean value - see http://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Collection.html#findAll(groovy.lang.Closure)
This should work (not tested):
plannings = plannings.findAll{planning-> planning.employees?.contains(employee)}
BTW: I wouldn't assign the filtered list to the origin plannings list. Extract a a new expressive variable like planingsOfEmployee or something similar.
Without more relevant details around your problem (what's the weird behavior? log traces? hibernate mappings?, etc.) all we can do is to speculate; and if I have to do so, I would say that most likely:
The employee object you are using for comparison is a detached one.
The employee object does not override meaningfully equals and hashCode
You use using this detached employee to do comparisons against against persisted employees (using planning.employees.contains(employee)) found inside planning
Under these circumstances the comparisons will never be true even when they may represent the same objects. If this is your case, you must either:
Use a persisted employee object to do the comparisons.
Or, implement equals and hashCode semantically meaningful for Employee
Hope this helps.
What is the difference between mappedBy and belongsTo for m-m relationships in Grails? How can the two be used in a same Domain?
I think there are 3 with 1 that has two formats:
There is belongsTo:
belongsTo=[something:Something] and belongsTo=Something or belongsTo=[Something,Another]
There is Something something
and finally hasOne=[something:Something]
When you declare Something something this actually creates a table cell called something_id
When you declare belongsTo=[something:Something] something_id isn't created and I think if I understand correctly that relationship is now managed by hibernate.
Points of reference Explain belongsTo in Grails and Grails hasOne vs. belongsTo
So in short one you manage the relationship through db and other is managed by hibernate.
How can the two be used in the same domain ?
Why would you need both if they are both pointing to the same parent ?
You can use either method for any relationship the belongsTo is a hibernate control mechanism telling it what / which way the relationship is so therefore the Parent must have Child child mapping
Where as Something something or Parent parent really has none of the above requirements. Hope it is making sense
Hi I have a simple problem.
My domain class is like this:
class Example {
long seq
hasMany = [example_array: ExampleData]
long count
}
class ExampleData {
String type
long description
static belongsTo = Example
static constraints = {
}
}
This results in 3 tables, like a many to many relation.
Why is this?
Thanks
The reason for the extra table is that you've modeled the relation only in one direction - an Example can access its ExampleData instances via the example_array Set that's added to your class bytecode because of the hasMany property, but an ExampleData instance has no way to reference its owning Example.
You added a belongsTo property, but only specified the class name. That's sufficient to configure ownership, cascaded deletes, etc. but doesn't provide a property in the class to access the Example instance.
If you change it to the other supported syntax it will work as you expected:
static belongsTo = [example: Example]
Here example will end up being the name of an Example property (and you can change it and/or example_array to any valid property name), which is basically the same as declaring
Example example
Now that both sides can access the other, the relationship is bidirectional and you no longer need the third table. That's because a 1-many is typically implemented using a foreign key in the child table, in this case in the table for ExampleData that points to the table for Example. That wasn't possible without a property in the class to wire up to that column, so the join table was necessary.
I believe that you have to map the BelongsTo, like this:
static belongsTo = [example:Example]
Hope it helps :)
From the definition of hasMany Grails will, by default, map this kind of relationship with a join table.That join table is the 3rd table you mentioned.No need to worry about that.
Well the one-to-many relationship is constructed by having additional table (i.e. Example_ExampleData) containing two columns each id fields from tables of the entities forming the relationship(i.e. Example and ExampleData).
The newly added table is child to parent tables – Example and ExampleData.
So in your case when you run your application the 3rd table gets created by Grails by default as your table relationship falls under the one-to-many relationship.
Suppose I have a domain class branch which has several members:
…
static hasMany = [ members:Member ];
…
Now suppose I want to have the number of members of that branch readily available, to have it displayed in the list and view actions, so perhaps storing that information into a variable in the domain class itself would be a good idea?
…
Integer memberCount = members.size();
static constraints = {
memberCount(editable:false);
}
…
(Is this the correct syntax?) Edit: This is not the correct syntax. I cannot assess the size of the members list, as it doesn’t exist yet and grails will complain about size() not being applicable to null objects. What else could I try?
However, as memberCount is now a variable in the domain class, it is possible to assign a value to it upon creation of the Branch (which is contra-intuitive) and it will not be updated automatically once a new Member is added.
It is of course possible to reach the desired result in a different way. I could manipulate the view.gsp and list.gsp in the /Branch directory, add some additional <td>s there etc. But that does not seem very elegant to me.
Basically, I think what I am looking for is some way to tell grails that a certain variable is derived, should not be setable by the user, but update whenever necessary. Is there such way?
You can add any property you don't want persisted to the transients static list:
static transients = ['memberCount']
See this page in the manual
Also, this StackOverflow question answers the same question
Also, a better way to do derived properties may be to use the Derived Properties feature of GORM
I'd like to know if it's possible to delete parent objects in a bidirectional 1:N association without a cascade delete. According to
http://grails.org/doc/1.0.x/guide/5.%20Object%20Relational%20Mapping%20%28GORM%29.html
...in a unidirectional relationship the parent end gets mapped with a 'save-update' and the child end with a 'none'. I've tried these settings for the bidirectional relationship, but not very surprisingly it didn't work. Specifically:
class Personnel {
...
}
static hasMany = [projectlead:Project, projectmanager:Project]
static mappedBy = [projectlead:'leaddeveloper', projectmanager:'projectmanager']
static mapping = {
projectlead cascade:'save-update'
projectmanager cascade:'save-update'
}
And here's the project class:
class Project {
...
}
static belongsTo = [leaddeveloper:Personnel, projectmanager:Personnel]
static mapping = {
leaddeveloper cascade:'none'
projectmanager cascade:'none'
}
I'd rather not redesign my application (by removing the "belongsTo" from the Project class) if there's a solution to this: the navigational access from both ends is very convenient and I don't have too much instances on the project end.
Also, if there's a way to implement this, it would be interesting to know, what happens with those active mappings afterwards, can I set them (or will they be set) to "null" for instance?
Appreciate any inputs on this matter.
By reading your question, I think that you want to delete "Personnel" object but leaving his "projects" untouched. Sadly, this can't be done with your current implementation. A "belongsTo" relationship means that every child object must has a Parent object. If you delete the Parent, the orphan will be deleted as well.
Another option that you could try without modifying too much the design is "marking as deleted". Add a "deleted" field in Personal, and in case you want to delete someone, just mark him as deleted. This will help you keep the historical data of projects, even after the project manager left.