How to maintain order in grails many-many relationship - grails

My project requires me to maintain the insertion and retrieval order in a many-many relationship. By default, groovy saves the elements as a Set in many-many relationship. I want to do it in a List. I am not sure how to update the relationship to use List instead of Set. Any help would be appreciated.
class Course{
static belongsTo = Teacher
static hasMany = [teacher:Teacher]
static mapping = {
teacher joinTable : [name: TeacherCourse]
}
}
class Teacher{
static hasMany = [course:Course]
static mapping = {
course joinTable : [name: TeacherCourse]
}
}
save() call on either Teacher or Course also inserts a new row in TeacherCourse table. It works with no issues. In Database there the tables are:-
Teacher (PK: Id)
Course (PK: Id)
TeacherCourse(PK: [Teacher_id,Course_id])
Is there a way I can maintain the order of insertion and retrieval in many-many relationship?
Thank you..
Edit
In controller save()
def courseInstance = new Course()
List <Teacher> teacherList= []
teacherList.add(Teacher.findById(65))
teacherList.add(Teacher.findById(36))
courseInstance.courseUnits = teacherList
courseInstance.save(flush:true)

Try this:
class Course {
List teachers
static belongsTo = Teacher
static hasMany = [teachers:Teacher]
static mapping = {
teachers joinTable : [name: TeacherCourse]
}
}
class Teacher {
List courses
static hasMany = [courses:Course]
static mapping = {
courses joinTable : [name: TeacherCourse]
}
}
Reference

Related

grails: multiple belongsTo with back reference

Is it possible to have a domain class that belongs to multiple domain classes with back reference? For instance:
class Person {
List<Book> books
static hasMany = [books: Book]
}
class Organization {
List<Books> books
static hasMany = [books: Book]
}
class Book {
def owner // what's the type?
static belongsTo = [Person, Books]
}
A Book can belong to a Person or an Organization, but not both.
Person and Organization have separate sequence IDs.
The solution I came up with is:
class Book {
Long ownerID
String ownerClass
static belongsTo = [Person, Books]
static transients = ['owner']
static constraints = {
ownerId(nullable:false, blank:false)
ownerClass(nullable:false, blank:false)
}
public BookOwner getOwner() {
grailsApplication.getArtefact("Domain", ownerClass)?.getClazz()?.get(ownerId)
}
}
where BookOwner is an Interface implemented by Person and Organization. So calling a bookInstance.owner will return a Person or Organization instance, both BookOwner.
My solution works well, but it doesn't feel right - a sure sign that I am not fully understanding what I'm doing. What's the best way to implement this? Should I completely give up on having the extremely convenient back reference?
Thank you
I guess, you should have made Owner superclass. Grails will create Owner table with field class meaning child class names (in your case: Person, Organization).

Grails Domain Class : hasOne, hasMany without belongsTo

I am new to Grails.
Can I use "hasOne" or "hasMany" without using "belongsTo" to another domain-class?
Thanks in advance.
Yes, you can. See examples in Grails doc: http://grails.org/doc/2.3.8/guide/GORM.html#manyToOneAndOneToOne
hasMany (without belongsTo) example from the doc:
A one-to-many relationship is when one class, example Author, has many
instances of another class, example Book. With Grails you define such
a relationship with the hasMany setting:
class Author {
static hasMany = [books: Book]
String name
}
class Book {
String title
}
In this case we have a unidirectional one-to-many. Grails will, by
default, map this kind of relationship with a join table.
hasOne (without belongsTo) example from the doc:
Example C
class Face {
static hasOne = [nose:Nose]
}
class Nose {
Face face
}
Note that using this property puts the foreign key on the inverse
table to the previous example, so in this case the foreign key column
is stored in the nose table inside a column called face_id. Also,
hasOne only works with bidirectional relationships.
Finally, it's a good idea to add a unique constraint on one side of
the one-to-one relationship:
class Face {
static hasOne = [nose:Nose]
static constraints = {
nose unique: true
}
}
class Nose {
Face face
}
Yes you can, but it behave differently
class Author {
static hasMany = [books: Book]
String name
}
class Book {
String title
}
In this case if you delete Author the books still existing and are independent.
class Author {
static hasMany = [books: Book]
String name
}
class Book {
String title
static belongsTo = [author: Author]
}
In this other case if you delete the Author it will delete all the books pf that author in cascade.
Many-to-one/one-to-one: saves and deletes cascade from the owner to the dependant (the class with the belongsTo).
One-to-many: saves always cascade from the one side to the many side, but if the many side has belongsTo, then deletes also cascade in that direction.
Many-to-many: only saves cascade from the "owner" to the "dependant", not deletes.
http://grails.org/doc/2.3.x/ref/Domain%20Classes/belongsTo.html
yes very easy like a class defintion but only specify hasMany but no need for hasOne
class Student {
String name
User userProfile
static hasMany =[files:File]
}
class User {
String uname
Student student
}
class File {
String path
Student student // specify the belongs to like this no belong to
}
Done!!

Groovy/Grails many-to-many delete relation

I have 2 domain class with a many to many relationship. When I delete the entity that belongs to the other, I have to remove the relation before in order to avoid a foreign key error. These relations are connected via the third class, third table in MySQL.
class City {
String nameCity
static hasMany = [visits:Visit]
/* FIRST VARIANT. REMOVES ONE VISIT ONLY */
def beforeDelete() {
Visit.withNewSession {
def visitList = Visit.findByCity(this)
visitList.each { it.delete(flush: true) }
}
}
}
//_____________________________________________
class Visit { // it is the relation class
City city
Person person
}
//_____________________________________________
class Person {
String namePerson
static hasMany = [visits:Visit]
}
So when I delete the relation between two classes, it removes one relation only. I mean, if we have 1 City and 1 Person, and try to delete this City, the app functions OK. But if you have more than one Person attached to the City, we will have:
"Cannot delete or update a parent row: a foreign key constraint fails". But one relation is deleted.
If I try to delete the City one more time, the second Person will be deleted. My app behaves like that until the last Person to be deleted. So, beforeDelete() method works great.
My problem is I don't understand how to create a collection of relations and remove them all in a cycle (loop). If I make like this:
class City {
String nameCity
static hasMany = [visits:Visit]
/* SECOND VARIANT. TYPE CAST EXCEPTION */
Collection<Visit> visitList() {
Visit.findByCity(this)
}
def beforeDelete() {
Visit.withNewSession {
visitList().each { it.delete(flush: true) }
}
}
}
I have org.codehaus.groovy.runtime.typehandling.GroovyCastException 'Cannot cast object 'mypackage.Visit : 1' with class 'mypackage.Visit' to class 'java.util.Collection'.
Any thoughts and help highly appreciated.
Have you tried the following? In theory should work...
class City {
String nameCity
static hasMany = [visits:Visit]
class Visit { // it is the relation class
City city
Person person
static belongsTo = [city:City, person:Person]
}
class Person {
String namePerson
static hasMany = [visits:Visit]
}
And just make a normal delete. In this way, if you delete a City or a Person, all its related visits will be deleted

How to implement Self-Referencing Relationships in Grails?

Given the following User class:
class User {
String name
static hasMany = [friends: User]
}
I want that a User can have many friends which are instances of the user domain class.
How do I have to implement the friend relationship of a user?
1. How Do you Define the relathionship
class User {
static hasMany = [ friends: User ]
static mappedBy = [ friends: 'friends' ] //this how you refer to it using GORM as well as Database
String name
String toString() {
name
}
def static constrains () {
name(nullable:false,required:true)
}
def static mapping={
/ / further database custom mappings ,like custom ID field/generation
}
}
2.How to save Data:
def init = {servletContext->
if(User?.list()==null) { // you need to import User class :)
def user = new User(name:"danielad")
def friends= new User(name:'confile')
def friends2=new User(name:'stackoverflow.com')
user.addToFriends(friends)
user.addToFriends(friends2)
user.save(flash:true)
}
}
3# . Your question is repeated on this stack overflow link :
Maintaining both sides of self-referential many-to-many relationship in Grails domain object
It looks like many-to-many relationship (one user has a lot of friends, and is a friend of a lot of users). So one of the solution will be to create new domain class, lets say it Frendship. And then modify User domain class like here:
class Friendship {
belongsTo = [
friend1: User
, friend2: User
]
}
class User{
String name
hasMany = [
hasFriends: Friendship
, isFriendOf: Friendship
]
static mappedBy = [
hasFriends: 'friend1'
, isFriendOf: 'frined2'
]
}

many-to-many retrieve only one row

I have a relationship between two domain class: User and Bank, user has many of bank and bank has many of user, the result table I call it as mm_user_banks that keep both table IDs for MM relationship.
class User {
String name
String password
Date createdAt = new Date()
Date loginAt
static hasMany = [banks:Bank]
static fetchMode = [banks: 'eager']
static constraints = {
}
static mapping = {
banks joinTable: [name: 'mm_user_banks', key: 'mm_user_id']
}
}
and Bank...
class Bank {
Long id
String name
static belongsTo = User
static hasMany = [users:User]
static constraints = {
}
static mapping = {
id generator: 'assigned'
users joinTable: [name: 'mm_user_banks', key: 'mm_bank_id'], lazy: false
}
}
I can save users with banks as well, but the problem is when I try to retrieve bank list from an user instance and it only fetch one row even if there is more than one row for this user in mm_user_banks table.
E.g:
User u = new User(name: 'user', password: 'pwd')
u.addToBanks(Bank.findById(1))
u.addToBanks(Bank.findById(2))
u.addToBanks(Bank.findById(3))
u.save(flush: true)
In database it is OK, fetching 3 rows, but when I get the user and see its bank list:
def user = User.findById(1) //OK
println "Size ${user.banks?.size()}" //only 1??? How?
Thanks in advance!
Just tested it out - "user.banks?.size()" returns "3". Are you sure that data in DB is OK?
Anyway, if you want to use eager fetching for collections then define it in "mapping" of User class (instead of "fetchMode" static field):
static mapping = {
banks joinTable: [name: 'mm_user_banks', key: 'mm_user_id'], fetch: 'join'
}
in Bank class use fetch: 'join' in mapping instead of lazy: false
Thanks so much, Sergei, but didn't worked out.
I fixed it in an ugly way, but this is was my remaining way out.
I created another domain class to mapping the MM table, so I did a mm_user_banks class. I use it to fetch records from bank or user and worked OK. To save banks for a user I actually do it in the old way as well, not changed from that. I guess this mighty not be the best way, but like I said, worked out.
I've tried "fetch: 'join'" and "lazy: false" and "static fetchMode = [banks: 'eager']" without success.
The new domain class is:
class UserBanks {
User user
Bank bank
static constraints = {
}
static mapping = {
table name: 'mm_user_banks'
user column: 'mm_user_id'
bank column: 'mm_bank_id'
}
}
I had the similar problem but in my case I had another relation between my equivalents to User and the Bank. This made the hasMany statement to use the wrong relation to map the many to many relation. In my case it was solved by adding a mappedBy statement to the relation:
class Bank{
...
static mappedBy=[users:'banks']
...
}
and
class User{
...
static mappedBy=[banks:'users']
...
}
or as it was in my case, since it was a uni-directional relation:
class ArticleGroup {
String name
static hasMany = [articles:Article]
static mappedBy = [articles: 'none']
static constraints = {
name(nullable:false, blank:false, unique:true, maxSize:100)
}
static mapping = {
table 'article_group'
sort 'name'
articles joinTable: [name:'article_group_article', key: 'articleGroup_id', column:'article_id'], fetch: 'join'
}

Resources