Deleted object would be re-saved in many-to-many relationship - grails

I'm using the Grails wiki example to setup a many-to-many relationship. When I make the Membership.unlink(employee, team) call, the m.delete causes the "Deleted object would be re-saved by cascade" error and I can't seem to get around this.

When you delete an instance that is linked to a hasMany relationship, you also have to remove the object from the 'many' side. For example:
employee.removeFromTeam(team)
employee.delete(flush: true)
It looks like in your example, you likely have a Membership class which holds a Team and an Employee relationship. In this case, you'll need to do the following:
membership.removeFromTeam(team)
membership.removeFromEmployee(employee)
membership.delete(flush: true)

Related

Strange activity from many to many in grails

Hi I am getting some strange activity from a many to many in grails.
It seems to be calling its self recursively.
my domains are set up like:
Product domain:
class Product {
String name
String comments
static hasMany = [components:Components]
}
Component domain:
class Components {
Product product
static hasMany = [alternatives:Product]
static belongsTo = Product
}
This seems to be causing a infinate loop and not saving the components correctly.
I know when using JSON.use("deep") on a Product I get a ../.. in components. The next strange thing is that. If I as for a product as JSON after I saved that product everything works fine, but when I try and get the same product as JSON later I get the ../.. in components.
I am totally lost about this.
If you require more details please let me know and I will me best to comply.
If you're going to have a many-to-many relationship you need to store the relationship data somewhere. If your relationship was one-to-many you could store them in the client table (like how you already have a component having one specific product in your component table) but in many to many you need the relationship to be its own table. To do this in Grails, use the JoinTable attribute or create a separate domain class to handle the relationship. Probably the fact that you have one-to-many relationship with Product already for Components and the many-to-many relationship with no join table is why you are getting the weird recursion issue.

Two Grails relationship between two tables - transient object exception

I'm working on a genealogy project. The problem is with two tables - the Person and Marriage tables.
The marriage class looks like this:
class Marriage implements Serializable{
Person husband
Person wife
String notes
}
The primary key is the husband.id and the wife.id.
The person class looks like this:
Class Person{
//lots of members
Marriage parents
}
Everything works, except adding parents to a person that's already created, but without parents, i.e. updating the person. There's no problem getting the right marriage to add to this person. Creating a person from scratch and adding a marriage to him works. I use much the same code. It works for save() but not for update()
Here's the problem: org.hibernate.TransientObjectException - object references an unsaved transient instance - save the transient instance before flushing: - it's the Marriage object. It exists in the database and is clearly visible. Using the Grails console I have no problem accessing it.
I've tried belongsTo and hasOne, no go.
Any idea what to do? I'd like to keep the composite key, it causes me no problems and prevents the same two people entering in another marriage - the notes can deal with that if they do.
what you see in the DB CAN NOT cause the TransientObjectException.
It looks like you are trying to save an perso instance, the marriage instance cannot be saved.
Print out the errors properties for both objects to see if they can be saved

How to make a domain class that belongs to one of a number of possible classes in Grails

I want to create a Comment class to allow my users to add comments to a number of different things.
class Comment {
User author
String text
static belongsTo = [post:Post, user:User]
static contraints= {
post(nullable:true)
user(nullable:true)
}
}
When I try and create a comment object using a post and without a user, i get the error "Property [user] of class [class Comment] cannot be null".
What is the best way to create a class that can belong to one of a number of different classes?
The best solution is to use a plugin like commentable.
However, if you want to roll your own solution then you need to understand that making something BelongTo another object makes it a required relationship. Thus it can't be null. Remove the belongs to and do a uni-directional one-to-many relationship. See the Grails documentation on modeling relationships.

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

merge two domain objects and reassign children to one of them in Grails

I have two entries in a domain entity that I want to merge. Let's call the parent House and the children Room. I have a situation where I want to merge two House domains that are actually the same. I have the logic to do this top level merge.
However, I want to know if there is a way in Grails to easily say, 'go through the domain objects and wherever there is a fk pointer to House, update that fk to a new value'.
The code would be something like this
houseInst1.magicMerge(houseInst2)
This would run the House merge as well as check for every domain object that has a pointer (fk) to House and update where it points to houseInst2 originally to point to houseInst1.
Update: One key feature is that I'd like this to work if someone adds another domain object with a link to the master object. eg. if someone added Mortgages later, I don't want to update all my merge logic, it should go and find that Mortgages is a child of House, and update accordingly.
Grails domain objects expose the hibernate merge() method, but this does something completely different: it merges a (possibly detached) object back into the persistence context.
I'm not aware of any built in functionality to merge two objects like you describe. I think you need to manually update the foreign keys as in Gregg's answer. A more efficient way to do the update would be through HQL like so:
Room.executeUpdate('update Room set house = :newHouse where house = :oldHouse',
[newHouse: newHouse, oldHouse: oldHouse])
Edit: to automatically update all the associations, you can interrogate the Artefact:
def artefact = grailsApplication.getArtefact("Domain", "House")
artefact.associationMap.values().each { associationClass ->
associationClass.executeUpdate("update ${associationClass.simpleName} set house = :newHouse where house = :oldHouse",
[newHouse: newHouse, oldHouse: oldHouse])
}
How about something like this? You'll want to do this before you get rid of the old house.
Room.findAllByHouse(oldHouse).each { room ->
room.house = newHouse
room.save()
}
I haven't tried this and I'm assuming a pretty standard OneToMany relationship between House and Room.

Resources