GORM one to one relationship while keeping existing entries - grails

After going over GORM's documentation, I've figured out how to create one-to-one relationships between objects. However, I haven't figured out how to go about enabling my desired relationship. The relationship I'm trying to create acts as a one-to-one, but keeps previous row entries for historical purposes.
For example, a Car can have multiple owners throughout its lifetime. If I have Car and Owner domain objects, how can I specify that the most recent entry in the Owners table for a given Car ID is the correct one?

There are lots of different ways to model this. IMO, one of the most flexible approaches is:
class User {
String name
static hasMany = [ownerships: Ownership]
}
class Car {
String name
static hasMany = [ownerships: Ownership]
}
class Ownership {
Date start
Date end
static belongsTo = [owner: User, car: Car]
}
For example, when Ann sells her car to Bob, we set the end-time of Ann's Ownership record to the time of sale and save a new Ownership record for Bob with the start-time set to the time of sale.
If getting the current owner of a car is an operation we frequently need to perform, we could add a currentOwner method to Car
class Car {
String name
static hasMany = [ownerships: Ownership]
Ownership currentOwner() {
// depending on how this method is used, you might want to
// return the User instead of the Ownership
Ownership.findByEndIsNullAndCar(this)
}
}

Related

Spring data for neo4j generating dynamic relationships between entities

I just started reading and playing with graph db and specifically Neo4j.
However I didn't encounter a solution for a use case that seems to me very common. Assume I have User object in my system and I want to maintain the relationships between users.
Examples:
User1 -> User2 - relationship sibling
UserX -> UserY - relationship parent
UserY -> UserX - relationship child
UserX -> UserZ - relationship teacher
I would like to store the relationship (the edge between the nodes) dynamically and not creating an entity with all possible relationships entities with annotation #Relationship.
Later, I would like to get a user and all his connections, but in run-time to figure out what is the type of the relationship.
Is this possible with spring data? or maybe it is not possible at all using Neo4j?
I will appreciate if you can point me to some reading for a solution to my problem.
Thank you.
It seems that you are only interested in the type of relationship after you would query for all, right?
You could use a #RelationshipEntity and add a property to it to define its type.
#RelationshipEntity(type = "USER_RELATION")
public class UserRelation {
//... #StartNode/#EndNode/#Id
private String type; // Here goes sibling, parent, etc.
}
And in your User entity you would just define one relationship.
#Entity
public class User {
// ... id, etc.
#Relationship(type = "USER_RELATION")
private List<UserRelation> userRelations;
}
This would always query every outgoing connection to another user.

Don't delete object of destination if it is in another Source in Coredata

I have a many to many relationship where entity are Employee and Department. Everything is going good but when i am trying to learn the relationship delete rules,i couldnot find out the right way.
I want to remove all the employee of the department if Entity Department gets deleted.But not those employee who are in another deparment.
Cascade Delete the objects at the destination of the relationship. For
example, if you delete a department, fire all the employees in that
department at the same time.
But i dont want to remove the employee if they are already in another department.One teacher teaching Swiftmay be in many departments "Computer","Electrical","Civil".How can i acheive that..Tried to use cascade but that removes all the Employees which i have set destination as below:
EDIT: Tried using nullify but deleting Source causes the deletion of all related Destination. However, deleting any single one Source simply causes Destination to forget about that particular Source.I gues,I need something intermediate nullify and cascade?
The following relationships will do what you want I think (I don't have the ability to test the answer here, but don't have rights to just leave a comment so you get the suggestion as an answer)
Employee -> Department Deny (can't fire an employee that is still assigned to a department).
Department -> Employee Cascade (fire all employees you can fire when the department is deleted, ie no longer has a department).
But it seems more reasonable to me set Department -> Employee to Nullify, and then make a separate scan for unassigned employees to fire outside the delete department code. This would also support general maintenance checks for employees that have had all their assignments removed.
In the case of mine i should not set the delete relationship to Cascade.But instead make both delete rule to nullify.And Check as in
class Departments: NSManagedObject {
// Insert code here to add functionality to your managed object subclass
override func prepareForDeletion() {
for teacher in self.teachers!{
if let tempTeach = teacher as? Teachers{
if tempTeach.departments?.count == 1{
self.managedObjectContext?.deleteObject(tempTeach)
}else{
print("this teacher is assigned to another department also so dont delete it")
}
}
}
}
}

Vinelab/NeoEloquent - Realtionship to a exisiting node

I am using Vinelab\NeoEloquent for a new project for Neo4j. I have a registration where people can supply interests (as nodes). When registering, first the user is created, then the interests are created (if they don't exist), an given a relationship of "Interested_In" from the person to the interest nodes.
Problem I am having is when the interest already exists (unique by name property) and I just want to create a relationship from the person created and the Interest node.
In my People Model I have (Since 1 person can have many interests):
public function interest(){
return $this->hasMany('App\Models\Interest','Interested_In');
}
In my create user function in my repository I have a section where it searches the Interests and returns one if one exists. Problem is I don't know how to then create the realtionship from People to Interest. I try to save it as
$interests = explode(',',$input['tags']);
$int = new NeoInterestRepository();
foreach($interests as $interest){
$existing = $int->find($interest);
if(count($existing)){
$person->interest()->save($existing);
}else{
$my_interest = $int->create($interest);
$person->interest()->save($my_interest);
}
}
But I get 'Argument 1 passed to Vinelab\NeoEloquent\Eloquent\Relations\HasOneOrMany::save() must be an instance of Illuminate\Database\Eloquent\Model, instance of Illuminate\Database\Eloquent\Collection given'
I see the associate() function but its only for BelongsTo which doesn't seem to apply.
Any ideas?

Removing multiple items from a Grails One to Many relationship

I'm creating an application using Grails 2.2.4 and Java 7 (these are constraints I cannot change) and I run into an odd behavior when trying to delete multiple entries in a Many-To-Many hasMany Set.
I have a class named Sport that contains the following:
Class Sport{
String name
static hasMany=[category:Category]
static belongsTo = [Category]
}
And another one named Category:
Class Category{
String name
static hasMany=[sports:Sport]
}
Now when in my CategoryController I try to delete multiple Sport instances from sports, my code compiles and runs without errors, but for reason only one of the selected instances is actually deleted.
If I get a Sport list and a Category id from a form and try to run the following code on every objet in the list:
def categoryInstance = Category.get(idCategory)
def sportInstance = Sport.get(idSport)
if(sportInstance!=null){
categoryInstance.removeFromSports(sportInstance)
}
categoryInstance.save()
Only the last instance is deleted.
If I run
def categoryInstance = Category.get(idCategory)
def sportInstance = Sport.get(idSport)
if(sportInstance!=null){
categoryInstance.removeFromSports(sportInstance)
categoryInstance.save()
}
Only the first one is deleted.
Note that this code is run from within a for loop over the params.sport.toList() list.
My guess is that this is either due to the fact that my sports Set is somehow "changed" after the first deletion and therefore Hibernate can't find the next instance, or that my save method commits the first change then "forgets" the next.
Any advice on how I can delete more than one instance at a time?
A workaround is to wrap the code for deleting a single association in a block of withNewSession + withNewTransaction
Sport.withNewSession {
Sport.withNewTransaction {
//delete 1 association here
}
}
It's not very elegant but works. Beware of a potential performance impact, as this will likely have many database roundtrips.
I don't know why this problem occurs, and googling didn't help either.
Another solution = workaround is to explicitly map the relationship as SportCategory, which you can then delete like any other object with SportCategory.delete().

How do hasMany and hasOne work in Grails?

I am having problems defining one-to-one and one-to-many relationships with domain classes.
I have the following domain classes
class Team {
static hasMany = [players: Player]
static hasOne = [coach: Coach]
}
class Person {
String name
}
class Player extends Person {
}
class Coach extends Person {
}
So my questions are:
1- Do I need to declare a variable team in Player and in Coach ?
2- Do I need to declare a belongsTo as well?
3- Considering the above classes, is it preferable to use hasOne?
Thank you.
There is a slight mistake with leebutt's answer.
The cascade is the other way around: if your coach/player has belongsTo set to Team, then a deletion of the team would cascade and delete the coach/player as well.
Only if you want to be able to easily navigate via player.team and coach.team
Depends on whether or not you want updates/deletes to cascade. I'd think not, as deleting a coach or player should not delete the team or vice versa?
hasOne looks to make sense for the team > coach relation, however it doesn't exist in Grails 1.1.1 or below. It might be in 1.2 (but it's not in the ref guide).
cheers
Lee

Resources