Search code examples
grailsgrails-orm

How to set proper relation among two classes


I am having some issues with setting relation among two classes. I have 2 classes, Student:

class Student {
   String name
   Guardian father
   Guardian mother
   Guardian local_guardian
}

and Guardian:

class Guardian {
   String name;
   static hasMany = [children:Student]
   static mappedBy = [children:'father']
}

Here, I used mappedBy to map Guardian object to father property . Unless mappedBy, I was getting error telling, should use mappedBy with any of the 3 Student class property. I tried this query to enter some sample data

new Student(name:"John", father: new Guardian(name:"Michael").save(),
            mother: new Guardian(name:"Mary").save(),
            local_guardian: new Guardian(name:"James").save()).save(flush:true);

The data is getting saved successfully but my problem is, Since I used mappedBy with 'father' property, I am able to use Guardian.children only with that father object. when I try to get list of children with mother and local_guardian object, (eg: mother.children) getting null result. I tried by adding with addTo on the many side like

Guardian.findByName("Mary").addToChildren(
   Student.findByName("John")).save(flush:true);

and tried accessing

Guardian.findByName("Mary").children 

Here, I got the result , but it moved the child from father to mother object, and no longer able to access father.children How will I solve this scenario? What I am trying to achieve is, I should be able to get list of children from all 3 of the Guardian object . Here One Student object is pointing to 3 Guardian objects (father, mother, local_guardian) . So I should be able to get the list of children by

  1. father.children
  2. mother.children
  3. local_guard.children

How will I set the proper relation among these classes to solve my problem?


Solution

  • If you want to implement this relation using hasMany then you will need to have three mappedBy in Guardian class.

    static hasMany = [children:Student, motherChildres:Student, localGuardianChildrens:Student]
       static mappedBy = [children:'father', motherChildrens:'mother', localGuardianChildrens: 'local_guardian']
    

    But this does not look good, instead you can implement a relation using a middle level domain class and add addToChildren and getChildrens methods in Guardian class like below.

    class GuardianChildren {
       Guardian guardian
       Student student
    
       constraints {
         student unique: ['guardian']
       }
    
    }
    
    Guardian {
      void addToChildrens(Student child) {
          new GuardianChildren(guardian:this, student:child).save()
       }
    
       @Transient
       List<Student> getChildrens() {
          return  GuardianChildren.findAllByGuardian(this).children
      }
    }
    
    Student {
    
       @Transient
       Guardian getMother() {
         //find guardin children where guardian type is mother and children is this student
       }
    
      @Transient
      Guardian getFather() {..}
    }
    

    Remove hasMany from Guardian and father/mother properties from Student. You will also probably need a type field in Guardian to specify if this is mother/father etc