Removing child-parent association in GORM - grails

Consider the following domain classes
class Business{
static hasMany = [contacts:ContactPerson]
}
class ContactPerson{
}
Given the following domain classes, say we use the following examples:
Alice is ACME's contact person. Bob and Carol are Calamity Corp's contact person.
Say I wanted to remove Bob in the ContactPerson table. Thus:
bob.delete(flush:true)
But the code will result to the server complaining about contraints:
ERROR: update or delete on table "contact_person" violates foreign key constraint
"fk4a69c6b329ef2fe1" on table "business_contact_person"
Detail: Key (id)=(174) is still referenced from table "business_contact_person".
In this context, the exception is thrown because Bob is still associated with Calamity Corp.
How do I delete Bob from the ContactPerson table? I wanted to remove Bob from the database altogether. I don't want to add belongsTo since I don't want to cascade the delete to Business' children (that is to say, if I delete Acme Corp from the database, I still want Alice to be in the system).
I've seen examples on disassociating the parent from the child but not the other way around.

I believe by simply adding a belongsTo, the cascade should work as expected...
class Business{
static hasMany = [ contacts:ContactPerson ]
}
class ContactPerson{
static belongsTo = [ business: Business ]
}

Ok. So with a little more digging, I finally got the codes that I wanted. John Rellis' post on Relationship Advice : Grails One-To-Many was especially helpful. In this article, he mentions how to query from children to parent (which is exactly what I am looking for).
Going back to the question, I wanted to remove Bob from the ContactPerson table but given the relationship between Business and ContactPerson simply calling bob.delete() simply would not do. What I need is to look for all businesses associated with Bob and remove the association. Thus the code below:
def bob = ContactPerson.get(params.id)
def criteria = Business.createCriteria()
def businesses = criteria.listDistinct{
createAlias("contactPersons","c")
eq("c.id", bob.id)
}
businesses.each{business->
business.removeFromContactPersons(bob)
business.save(flush:true)
}
bob.delete(flush:true)
I also added a new mapping to the Business domain model:
static mapping = {
children cascade:"all-delete-orphan"
}

Related

Grails 3: find domains that were added to another one in many-to-many relationship (No value specified for parameter 1

I'm a Grails newbie and I found the following obstacle:
I have 2 domains: Course and Student, they have a many-to-many relationship (a Course can have several students, a student can enroll in several courses) and the student belongs to the course.
So, when I add a student to a course, I want to be able to find what Courses have added a specific student.
I tried to use:
def s = Student.get(id)
def c = Course.findAllByStudents(s)
But grails keeps telling me "No value specified for parameter 1".
Can you guys throw some light into this?
Course.findAllByStudents expects as parameter Set of Students but you are supplying it with single instance of Student, that's why you are getting "No value specified for parameter 1".
To find in what Courses is Student. If you created domain classes like this:
class Course {
//some Course attributes
static hasMany = [students: Student]
}
class Student {
//some Student attributes
static hasMany = [courses: Course]
static belongsTo = Course
}
then you can simply use s.courses.
If you are not two-way mapping that relationship. You can create criteria like this:
Course.withCriteria {
createAlias 'students', 's'
eq 's.elements', s
}

Understanding hasMany behavior in grails and how to save a relationship

I'm making a model where a User fills out many questionnaires and the responses get saved to Questionresponse. I'm on grails 2.5.2
Test1
So I have two models
class User {
String username
...
static hasMany = [reponse: QuestionResponse]
}
class QuestionResponse {
String question_1
String question_2
...
}
With the above, a new DB table is created: user_questionresponse with two columns user_questionresponses_id and questionresponse_id. This seems like what I want. A user would have many questionresponses and those relationships would be saved in this table. However, I can't find out how to save data to this table.
For example, if I do:
def user = springSecurityService.currentUser
def questionnaire = new QuestionResponse(question_1: "foo", question_2: "bar")
//How do I link the user to this newly created questionnaire?
user.addToResponse(q).save(flush: true) //DOES NOT WORK.
Test2 (just add belongsTo)
class User {
String username
...
static hasMany = [reponse: QuestionResponse]
}
class QuestionResponse {
String question_1
String question_2
static belongsTo = [user: User]
...
}
If I add belongsTo to QuestionResponse a new column, user_id, gets created in the DB. Now if I run the same code as above, this user_id column has the id populated with that of the current user. However, the relationship table, user_questionresponse is still empty.
I am aware of the approach mentioned by Burt but I assume that should be required only for ManyToMany relationship. If that is required for all relationship, why isn't that the default?
In your first case, you have a OneToMany relationship between User and QuestionResponse with no side being the owner of the relationship. In this case to maintain the relationship between User and QuestionResponse, a third table is required. To persist data you need to do the:
userInstance.addToResponse(new QuestionResponse(question_1: "foo", question_2: "bar")).save(flush: true, failOnError: true)
You are doing user.addToReponse(q) instead it should be user.addToReponse(questionnaire), if it's not a typo and the data is actually not being stored, then check by adding the failOnError parameter to save() method. Sometimes grails save() method fails silently, it should tell you if this is the case.
In second case, you have added the parent to the relationship, so that means you don't need the third table to maintain the relationship. Grails will not create and populate the third table in this case.
The second approach (adding belongsTo in QuestionResponse) seems the right thing to do in your case, since QuestionResponse objects cannot exists without a user and cannot belong to different users.
In that case there's no need to use a third table.
When you run the app for the first time, grails created the relation table (because there was no belongsTo). When you run the app again with belongsTo grails adds the user_id field but DOES NOT DROP the relation table. That's why the table is there and is empty: it's not needed, but grails database auto-update feature only adds things, it does not remove anything.
The same applies to fields: if you remove a field from an entity you have to manually remove it from the database.

Grails belongsTo multiple classes

I have a domain class that can belong to one of several classes. I'm seeing validation errors when I try to save.
class Teacher {
Book book
}
class Student {
Book book
}
// book can belong to either a student or a teacher
class Book {
static belongsTo = [student : Student, teacher : Teacher]
}
The validation error suggests that a book must belong to BOTH a student and a teacher (neither can be null), but I want to model it so that it can belong to either. How do I do this please?
Please disregard the fact that for my example you could change it so that a Person owns a book and a Teacher and a Student are both types of Person - I want to know how how to create the correct belongsTo.
Edit to explain reasoning behind requirement:
There will be 3 tables created: Book, Student and Teacher. I need to be able to create an index on the Book class that refers to Student and Teacher. This is so the query that is "find all books that belong to Teacher A" can be made as fast as possible.
If there was just a single belongsTo (example shown if for owner teacher)then this is done like this:
static mapping = {
teacher index: 'teacher_idx'
}
Well this is very much doable, its just that your approach is wrong here.
belongsTo is used in a way when an entity must and must be mapped with some other entity. There is nothing like either of them.
What you can do is
1. create an Abstract Domain `Book`
2. create an Domain `StudentBook` it belongs to `Student`
3. create an Domain `TeacherBook` it belongs to `Teacher`
So here only one table will be created for the three Domains, named as Book. This table will contain a field class which will determine if the book belongs to Student or Teacher.
If I understand you then you can use other version of belongsTo which does not store back reference of Owner Class e.g
class Book {
static belongsTo = [Student, Teacher]
}
Ref

GORM - Model Relationships Between Like Entities

For my project I'm using Grails, but this is kind of a general ORM question.
I'm new to ORMs and ER diagrams, and trying to figure out how to best describe/implement the following:
I have 2 Entities: User, Connection
A Connection consists of 2 Users (and other primitive attributes). A user can be found in more than one Connection. How would you describe the relationship between User and Connection? I don't know what you would call it, 2 to many? How would you draw it in an ER diagram.
In GORM, should it be a bi-directional relationship?
Edit
As an added requirement, assume the users have specific roles in the relationship. Like student and teacher. So Connection would have student and teacher properties of type User.
the problem is not GORM, your problem deals with Entities. Before you code Domain classes, you have to image distinctly what info you would like to keep and operate. According your question and comments you prefer to use any RDBS. So let's to try to image easy simple tables (don't care about any ORM, Grails, bi\uni-directions) and try to fill this tables mock details.
Users
nickName (String)
otherUsersFields
Connection
teacher (Users)
student (Users)
otherConnectionFields
well, now we know all Users and all Connections. For given connection we can say who is teacher - connection.teacher and student - connection.student.
Note: any Connection has only two users.
pay attention to Users. Any User can be Student and Teacher. If User can be only Student or Teacher you will have to add additional field(s), for example
Users
nickName (String)
isTeacher (boolean)
otherUsersFields
now we have a list of user and know who is st. or tech.
How can I get all connections for given user?
GORM offers: Connection.findAllByStudent( givenUser), Connection.findAllByTeacher( givenUser)
Do this tables show your info completely?
I think what you want can be described as a many-to-many relationship, with some sort of constraint applied on Connection users collection. As for uni/bi-directional, I believe you can accomplish either depending on your use case - although uni-directional is probably harder to map/configure.
I haven't tested this, but a bi-directional many-to-many should look like this
class Connection {
...
Set users = [] //ensure users exists, constraints won't work on null
static belongsTo = [User]
static hasMany = [users: User]
static constraints = {
users maxSize: 2
}
}
class User {
...
static hasMany = [connections: Connection]
}
I don't have a uni-directional example off the top of my head, but I believe you may need to use an additional mapping class.
Again, I haven't tested this, but here's an example of uni-directional many-to-many with a mapping class
class Connection {
...
Set users = []
static hasMany = [users: ConnectionUser]
static constraints = {
users maxSize: 2
}
}
class User {
...
}
class ConnectionUser {
User user
Connection connection
//or for cascading effects
//static belongsTo = [connection: Connection]
...
... //lots of additional code to manage adding,
... //removing, updating Connection-to-User relationships
}
Connection knows about Users, but Users do not know about Connections they belong to. If you go the mapping class route, you'll need to manage the Connection to User relationships manually. Take a look at Spring Security Core PersonAuthority class for an example of mapping class.

How to define association relationship in grails

UPDATED
I have a domain classes as below
class Training{
// has one createdBy object references User domain and
// has one course object references Course domain
// has One Trainer1 and Trainer2 objects refernces Trainer Object.
}
class Trainer{
String name
//can have many trainings.
//If Trainer gets deleted, the trainings of him must be deleted
}
Class User{
String name
// can have many trainings.
}
class Course{
String name
//If Course gets deleted, Trainings of this course must be deleted
// can have many trainings.
}
I have got a training create page, Where I have to populate already saved Course, User, Trainer1 and Trainer2. I am not saving them while Creating the training.
So, How to specify the relationship in grails
You did not put any effort to searching answer for yourslef. There are plenty basic examples and blog posts how to map relations in Grails. You should start with Grails documentation of GORM - Grails' object relational mapping. You can find it here.
I see some minor flaws in yout initial design: ie why should training be deleted if user is deleted when trainings will obviously tie with many users. Can training exists without trainers or vice versa ?
I would start with something like this:
Class Training {
static hasMany = [users: User, trainers: Trainer]
static belongsTo = Course
}
Class Trainer {
String name
}
Class User {
String name
}
Class Course {
String name
static hasMany = [trainings: Training]
}
EDIT: I have to agree with Tomasz, you have jumped here too early without searching for answers yourself. Grails.org has good documentation about GORM with examples too.

Resources