Significance of “mappedBy” in Grails Domain

3 min read
Share:

“mappedBy” is a static map which is used to determine and change the way two associated domain classes interact with each other.

Let’s start with the role of “mappedBy” in one-to-many relationships.

Consider the following Example:-

[code]class Team {
    static hasMany = [members: TeamMember]
}[/code]

 

[code]class TeamMember {
    Team memberOf
    Team captainOf
}[/code]

The Team domain contains a one-to-many association (members) with TeamMember domain which has multiple properties (memberOf, captainOf) of Team type. This makes the association bi-directional.

Now, Grails won’t know which of the properties (memberOf or captainOf) of TeamMember domain it needs to involve while creating this bi-directional one-to-many association and it will give the following error:

"Property [members] in class [class Team] is a bidirectional one-to-many 
with two possible properties on the inverse side. Either name one of the properties on 
other side of the relationship [team] or use the 'mappedBy' static to define the property 
that the relationship is mapped with. Example: static mappedBy = [members:'myprop']"

To resolve this, we declare “mappedBy” on the “one” side of this association:

[code]class Team {
    static hasMany = [members: TeamMember]
    static mappedBy = [members: ‘memberOf’]
}[/code]

This way Grails would know that [members] of Team has a bi-directional one-to-many association with [memberOf] of TeamMember and it will infer that Team is associated with TeamMember in a one-to-one relationship using the property [captainOf].


On that note, lets consider the case of many-to-many relationships.

Here’s an example :-

[code]class User {
    static hasMany = [writtenPosts: Article, subscribedPosts: Article]
}[/code]

[code]class Article {
    User writer
    static hasMany = [subscribers: User]
    static belongsTo = [User]
}[/code]

These domains are associated with each other in 2 ways:

  1. [writtenPosts] of User is associatemany-to-one relationship.d with [writer] of Article in a bi-directional
  2. [subscribedPosts] of User is associated with [subscribers] of Article in a many-to-many relationship.

With this code, Grails will create 4 tables for these 2 classes:

1. user(id, version, name)
2. article(id, version, description, writer_id)
3. user_subscribed_posts(user_id, article_id)
4. user_written_posts(user_id, article_id)

The 4th table is redundant as the same information would be stored in [writer_id] column of article table. To prevent this, we declare “mappedBy” in the User domain specifying:

  1. [writtenPosts] of User is associated with [writer] of [Article].
  2. [subscribedPosts] of User is associated with [subscribers] of Article.

 

[code]class User {
    static hasMany = [writtenPosts: Article, subscribedPosts: Article]
    static mappedBy = [writtenPosts: ‘writer’, subscribedPosts: ‘subscribers’]
}[/code]

Now, when this code runs only 3 tables are created:

1. user(id, version, name)
2. article(id, version, description, writer_id)
3. user_subscribed_posts(user_id, article_id)

By using “mappedBy” we can direct Grails towards the correct relationship or change the inferred relationship between multiple domains to suite our needs.

I came by this topic while perusing through Grails wiki and thought of sharing this with everyone.

Hope you enjoyed reading this blog.

comments ( 1 )

Leave a Reply

Your email address will not be published. Required fields are marked *