Significance of “mappedBy” in Grails Domain
“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:
- [writtenPosts] of User is associatemany-to-one relationship.d with [writer] of Article in a bi-directional
- [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:
- [writtenPosts] of User is associated with [writer] of [Article].
- [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.
Thank you for the post. How would one implement tree structure in Gorm please? Thanks