views:

170

answers:

4

I need to create a many-to-many relationship in Grails.

I have a "Question" domain and a "Tag" domain. A Question can have 0 or more tags. A Tag can have 0 or more Questions.

If I put a "hasMany" on each sides, it gives me an error saying I need a "belongTo" somewhere. However, adding a belongsTo means that the owner must exist...

Like I said, a Tag could have 0 questions, and a Question could have 0 tags. There is no concept of an owner, it's a many-to-many!

What am I supposed to do?

A: 

I haven't tried it, but I think the mappedBy property can be used to solve this.

Michael Borgwardt
+1  A: 

If your main concern is the cascading delete, you can take a look at 5.5.2.9 in the grails docs to manually disable it for the mapping.

Sev
A: 

Checkout the Taggable Plugin.

It seems to solve the problem you are having and you could look at the source code if you want to see how they modeled the relationship. BTW this plugin was originally created by Graeme Rocher who is the lead developer on Grails.

Heinrich Filter
+1  A: 

you can do this (please see the code below). but does it make sense to have a question tag with out both a question and a tag?

    package m2msansbt

    class Question {
        String toString() { return name }
        String name
        static hasMany=[questionTags:QuestionTag]
        static constraints = {
        }
    }
    package m2msansbt

    class Tag {
        String toString() { return name }
        String name
        static hasMany=[questionTags:QuestionTag]
        static constraints = {
        }
    }
package m2msansbt

class QuestionTag {
    Question question
    Tag tag
    static QuestionTag link(Question question,Tag tag) {
        QuestionTag questionTag=QuestionTag.findByQuestionAndTag(question,tag)
        if (!questionTag) {
            questionTag = new QuestionTag()
            question?.addToQuestionTags(questionTag)
            tag?.addToQuestionTags(questionTag)
            questionTag.save() 

        }
        return questionTag
    }
    static void unlink(Question question,Tag tag) {
        QuestionTag questionTag=QuestionTag.findByQuestionAndTag(question,tag)
        if (questionTag) {
            question?.removeFromQuestionTags(questionTag)
            tag?.removeFromQuestionTags(questionTag)
            questionTag.delete()
        }
    }
    static constraints = {
    }
}

 import m2msansbt.*
 class BootStrap {

         def init = { servletContext ->
            Question q1=new Question(name:'q1')
            Tag t1=new Tag(name:'t1')
            Tag t2=new Tag(name:'t2')
            q1.save()
            t1.save()
            t2.save()
            QuestionTag q1t1=QuestionTag.link(q1,t1)
            q1t1.save()
            QuestionTag q1t2=QuestionTag.link(q1,t2)
            q1t2.save()
            q1.save()
            t1.save()
         }
         def destroy = {
         }
    }
Ray Tayek