您的位置:首页 > 大数据 > 人工智能

Many-to-many relationship mapping with GORM/Grails

2014-08-11 13:28 351 查看


I’ve been working on a pet project in my spare time – a sort of twitter clone that authenticates against Atlassian Crowd. I’m using the awesome Grails/Crowd
plugin, which is pretty seamless (but needs a bit of internal polishing).

I’ve only scratched the surface of Grails, but here are a few things I’ve run into as a Grails newb.

Many-to-many relationships and cascading updates

GORM (Grails’s abstraction of Hibernate) lets you define a many-to-many relationship like this:

class User {
String name
static hasMany = [groups: Group]
}

class Group {
String name
static hasMany = [members : User]
static belongsTo = User
}


This relationship can be accessed through some helpful dynamic methods that Grails provides:

new User(name: "foo").addToGroups(name: "bar").save()
// creates a new user AND group, saves both of them
// and the relationship

def user = new User(name: "foo").save()
new Group(name: "bar").save().addToMembers(user)
// as above, but addToMembers will not cascade the relationship
// to the user


The crucial part here is the 
belongsTo
 property of the domain classes. This tells GORM which class should “own” the relationship. What this means is that if you want the relationship to cascade through both objects, you will need to call the 
addTo*
 method
on the owning object.

Many-to-many relationships with the same class

Back to the pet project – one of the features I really wanted was the ability to subscribe to status updates for a whole group.

Here’s a quick ERD (generated by the excellent IDEA/Grails integration) of the domain classes:



You can quickly see that there are two many-to-many relationships between the classes 
User
 and 
Group
.

The code looks something like this now (other stuff stripped out):

class User {
String name
static hasMany = [groups: Group, groupSubscriptions: Group]
static mappedBy = [groups: "members"]
}

class Group {
String name
static hasMany = [members : User]
static belongsTo = User
static mapping = {
// we can't have a table called group
table "group_"
}
}


I thought that Grails would be smart enough to see what I was doing, but I was wrong (for various reasons). To cut to the chase, here’s the necessary code to implement this:

class User {
String name
static hasMany = [groups: Group, groupSubscriptions: Group]
static mappedBy = [groups: "members",
groupSubscriptions: "subscribers"]

static mapping = {
groupSubscriptions joinTable: "user_group_s"
}
}

class Group {
String name
static hasMany = [members : User, subscribers: User]
static belongsTo = User

static mapping = {
// we can't have a table called group
table "group_"
subscribers joinTable: "user_group_s"
}
}


Grails will create two relationship tables 
user_group_
 and
user_group_s
. Having the back reference from 
Group
 to 
User
isn’t so bad, since the collection is lazy loaded. I would have just preferred not to pollute
the domain class.

Conclusion

I hope that someone out there finds this information useful, I’d hate to see another Grails newb fall into this big dark pit that I call lack of documentation.

That said, my experience with Grails and Groovy so far has been pretty awesome. If you’re looking to develop a web-app rapidly, I’d definitely be looking at Grails as an option.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息