Grails hasOne unidirectional - grails

Currently I'm having some trouble, creating an unidirectional relationship in Grails.
I have a class Toilet with an Attribute Address.
This Address is a seperate class.
The Address can - theoretically - still exist, if the Toilet-Object, which the Address is associated with, gets deleted.
The toilet will stay, too, if the address gets deleted.
GORM's hasOne is not what i need, because it creates a bidirectional relation.
Defining an attribute of the type class only results in a non-persisted Address (despite it's own table) - that means, the association of the Address to the Toilet-Object doesn't exist
I'm not really familiar with these kinds of relationships, so I would really appreciate a solution or another way to accomplish my goal
Hope my problem is clear - if not comment, and I will try to add further explanations

taken from
http://grails.org/doc/1.0.x/guide/5.%20Object%20Relational%20Mapping%20(GORM).html
5.3.3 Understanding Cascading Updates and Deletes
It is critical that you understand how cascading updates and deletes work when using GORM. The key part to remember is the belongsTo setting which controls which class "owns" a relationship.
Whether it is a one-to-one, one-to-many or many-to-many if you define belongsTo updates and deletes will cascade from the owning class to its possessions (the other side of the relationship).
If you do not define belongsTo then no cascades will happen and you will have to manually save each object.
So.....if you do not use belongsTo then if you manually save each object you should not have a problem.

If the address on Toilet is a simple association without a hasOne or belongsTo mapping, then no operations will be cascaded.
That means you'll have to save the address, assign it toilet.address, and save the toilet.

Found the solution.
What I left out, was the implemenation of an interface in the Toilet class.
The problem was (as a reminder) that the relationship of the address within the toilet class wasn't saved to the database.
This was a problem of the interface itself - in this interface, getters and setters were defined and had to be implemented (the way an interface works - obviously). The problem here was, that the setter of the Address-Attribute expected the Type IAddress.
I overloaded the setter to also receive a parameter of the type Address.
With this change, the relationship between Toilet and Address is saved correctly to the database - the ID of the Address is saved in the table of the Toilet.
I think the definition of the setter is just a mistake (i have no influence on the interface), but with this workaround i can get it to work anyways
Hope this explanation helps others too.

Why not have a class which models the association ?
class ToiletAddress {
Toilet toilet
Address address
...
}
... and then simply wrap your logic into a service where you assign addresses to toilets, and delete toilets or addresses.
Using constraints you can define what kind of association it is. eg 1-1, 1-n (both sides), and n-m
static constraints = {
address unique: ['toilet']
toilet validator: {val, obj -> ... }
}

Related

Grails: Simple hasMany relation create more tables than necessary

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.

One-to-many relationship not working as expected

I'm having some problems getting a one to many relationship in grails working properly.
I have a person instance and this person has relationships to other persons. This relationship is defined in a relationship object.
The relevant code is as follows.
class Person {
static hasMany = [relationships:Relationship]
String name
}
class Relationship {
Person relationShipTo
// Enum containing married, living together, parent etc.
RelationshipType typeOfRelationship
}
Now what i want is a one to many reference to that relationship to be persisted but what happens in grails is that it seems to think the relationShipTo instance is refering back to the Person that has this relationship with someone else, and not to the other person.
So a person has a reference to a relationship, and that relationship has a type and a reference to the person with whom you have a relationship with.
I'm not able to change the domain model for this. Is there any way of accomplishing what i want?
What is currently happening if i use the generated views and controllers for the Relationship and try to create a relationship with a type and a person it is refering to, only the type is persisted and the person is ignored. When i then try to add it to the person in the persons edit or create page, all the relationShipTo properties of the relationships i add is saved with the id of the person.
Hopefully what i wrote is understandable.
Finally got it working.
Had to add a static mappedBy =[relationship: 'belongsTo'] to person
and a static belongsTo = [belongsTo: Person].
Not exactly how i wanted it but it works and is an ok compromise

Should removeFrom* method remove child item from a DB or it should just remove the parent-child relation?

The question is in the subj.
Currently, the behavior I observe is that when I call Parent.removeFromChilds(child), child is not removed from my DB (i.e. I can find it with Child.findBy...(args)).
I'm curious if it's the correct behavior. If yes - what's the best way to remove both relation and child within one transaction?
If no - what may I do wrong?
By default, deletes cascade if you delete the owning side of a one to many. If you just remove the child, it will not delete. You can change that by specifying the custom cascading behavior of 'all-delete-orphan' on the owning side of the relationship. From the Grails doc:
class Person {
String firstName
static hasMany = [addresses: Address]
static mapping = { addresses cascade: "all-delete-orphan" } }
Update
Part 2 of GORM Gotchas has a really good breakdown of the not-so-obvious addTo and removeFrom behavior. I think it contains the exact information you're looking for.

How to prevent cascade delete for bidirectional associations?

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.

Grails - Need to restrict fetched rows based on condition on join table

I have these two domains Car and Driver which have many-to-many relationship. This association is defined in table tblCarsDrivers which has, not surprisingly, primary keys of both the tables BUT additionally also has another boolean field deleted. Herein lies the problem. When I find/get query on domain Car, I am fetched all related drivers irrespective of their deleted status in tblCarsDrivers, which is expected.
I need to put a clause/constraint to
exclude the deleted associations from the
list of fetched records.
PS: I tried using an association domain CarDriver in joinTable name but that seems not to work. Apparently it expects only table names, not maps.
PPS: I know its unnatural to have any other fields besides the mapping keys in mapping table but this is how I got it and it cant be changed.
Car domain is defined as such -
class Car {
Integer id
String name
static hasMany = [drivers:Driver]
static mapping = {
table 'tblCars'
version false
drivers joinTable:[name: 'tblCarsDrivers',column:'driverid',key:'carid']
}
}
Thanks!
I know its unnatural to have any other
fields besides the mapping keys in
mapping table but this is how I got it
and it cant be changed.
This is not at all unusual. If you want to store properties about the relationship, this is the obvious solution. You should reinstate your association domain CarDriver which has a deleted property in addition to a relationship to Car and Driver, and you should then be able to write a query which excludes the deleted drivers.
A comprehensive example of how to define such a mapping is provided here.

Resources