[英]Grails inheritance and conflicting one-to-many and many-to-many relationship
I'm learning grails by trying to create a simple twitter copy. 我通过尝试创建简单的Twitter副本来学习grails。 I'm currently trying to incorporate followers and groups.
我目前正在尝试纳入关注者和群组。 I originally came up with a very basic database structure, and I've had no luck in implementing it.
我最初想出了一个非常基本的数据库结构,但在实现它方面却没有运气。 The design for relationships is as follows:
关系的设计如下:
Person:
has many: Groups, Tweets, (Person as followers through User2Person)
Group:
has many: (Person as followers through User2Person)
belongs to: Person as owner
User2Person:
belongs to: (Person or Group)
belongs to: Person
Basically, I want Person and Group to be an instance of User, and then create a table that maps User to Person. 基本上,我希望Person和Group成为User的实例,然后创建一个将User映射到Person的表。 This way, only one table is created/used for the relationship between Group2Person and Person2Person.
这样,仅一个表被创建/用于Group2Person和Person2Person之间的关系。
More information: A Group is created by a Person and so it should have an "owner" (person_id). 详细信息:组是由人员创建的,因此它应该具有“所有者”(person_id)。 It also has many followers (ie members).
它还有许多关注者(即成员)。 Group cannot follow other groups, but a Person can follow either another Person or a Group.
组不能跟随其他组,但是一个人可以跟随另一个人或一个组。
Below is how I implemented this in grails: 下面是我如何在grails中实现此功能:
User 用户
abstract class User {
static hasMany = [followers: Person]
static mappedBy = [followers: "followed"]
String name
Date dateCreated
Date lastUpdated
static constraints = {
name shared: "mustFill", size: 3..20
}
}
Person 人
class Person extends User {
static belongsTo = [followed: User]
static hasMany = [tweets: Tweet, groups: Group]
static mappedBy = [groups: "owner"]
String username
String email
static constraints = {
username shared: "mustFill", unique: true, size: 4..15
email shared: "mustFill", email: true
}
static mapping = {
tweets sort: 'dateCreated', order: 'desc'
}
}
Group 组
class Group extends User {
Person owner
String description
def getTweets() {
return followers.tweets.flatten()
}
static transients = {
tweets
}
}
Tweet (Just in case?) 鸣叫 (以防万一?)
class Tweet {
static belongsTo = [author: Person]
String text
Date dateCreated
static constraints = {
text shared: "mustFill", maxSize: 140
}
}
When I run the cmd grails schema-export
, I get the following error: "| Error Error loading plugin manager: Domain classes [class tweeter.Group] and [class tweeter.Person] cannot own each other in a many-to-many relationship. Both contain belongsTo definitions that reference each other. (Use --stacktrace to see the full trace)" 当我运行cmd
grails schema-export
,出现以下错误:“ |错误加载插件管理器时出错:域类[tweeter.Group]和[tweeter.Person类]不能多对多拥有关系。两者都包含相互引用的belongsTo定义。(使用--stacktrace查看完整的跟踪)”
I was able to get the database to create almost the correct schema. 我能够使数据库创建几乎正确的架构。 Unfortunately, the join table's primary key for User2Person (aka followers) used (user_id, person_id).
不幸的是,使用了User2Person(又名追随者)联接表的主键(user_id,person_id)。 That meant that I could not have two records such as: (1, 2) and (2, 1) (eg two users are following each other).
那意味着我不能有两个记录,例如:(1、2)和(2、1)(例如,两个用户彼此关注)。 Below is the updated classes ( commit ):
下面是更新的类( commit ):
User 用户
class User {
static belongsTo = Person
static hasMany = [followers: Person]
String name
Date dateCreated
Date lastUpdated
static constraints = {
name shared: "mustFill", size: 3..20
}
}
Person 人
class Person extends User {
static hasMany = [tweets: Tweet, groups: Group, follows: User]
static mappedBy = [tweets: "author", groups: "owner"]
String username
String email
static constraints = {
username shared: "mustFill", unique: true, size: 4..15
email shared: "mustFill", email: true
}
static mapping = {
tweets sort: 'dateCreated', order: 'desc'
}
}
The follower table in the schema looked like: 模式中的关注者表如下所示:
create table user_follows (
user_id bigint,
follows__id bigint,
primary_key(user_id, follows__id)
)
I scoured the web for information about changing the primary key for a join table. 我在网上搜索了有关更改联接表主键的信息。 The best I could find was about using code like:
我能找到的最好的方法是使用类似以下的代码:
static mappedBy = { followers joinTable: [name:"someName", ...] }
Unfortunately, I had a hard time finding good documentation on the joinTable mapping, and most sources seemed to indicate that it was not possible to change the primary key of join tables easily. 不幸的是,我很难找到有关joinTable映射的良好文档,并且大多数资料似乎都表明不可能轻易更改连接表的主键。 I then decided to use a separate domain class to define the join table following this guide: Many-to-Many Mapping without Hibernate XML.
然后,我决定按照本指南使用单独的域类来定义联接表:没有Hibernate XML的多对多映射。 Below is the final updated code ( commit ):
以下是最终更新的代码( commit ):
User 用户
class User {
static belongsTo = Person
static hasMany = [people: UserFollower]
static mappedBy = [people: "followed"]
String name
Date dateCreated
Date lastUpdated
static constraints = {
name shared: "mustFill", size: 3..20
}
static transients = {
followers
}
def getFollowers() {
return people.collect { it.follower }
}
void addToFollowers(Person person) {
UserFollower.link(this, person)
}
void removeFromFollowers(Person person) {
UserFollower.unlink(this, person)
}
}
Person 人
class Person extends User {
static hasMany = [tweets: Tweet, groups: Group, users: UserFollower]
static mappedBy = [tweets: "author", groups: "owner", users:"follower"]
String username
String email
static constraints = {
username shared: "mustFill", unique: true, size: 4..15
email shared: "mustFill", email: true
}
static mapping = {
tweets sort: 'dateCreated', order: 'desc'
}
static transients = {
follows
}
def getFollows() {
return users.collect { it.followed }
}
void addToFollows(User user) {
UserFollower.link(user, this)
}
void removeFromFollows(User user) {
UserFollower.unlink(user, this)
}
}
UserFollower UserFollower
class UserFollower {
User followed
Person follower
static constraints = {
followed nullable: false
follower nullable: false
}
static void link(User user, Person person) {
UserFollower f = UserFollower.findByFollowedAndFollower(user, person)
if(!f) {
f = new UserFollower()
user.addToPeople(f)
person.addToUsers(f)
f.save()
}
}
static void unlink(User user, Person person) {
UserFollower f = UserFollower.findByFollowedAndFollower(user, person)
if(f) {
f = new UserFollower()
user.removeFromPeople(f)
person.removeFromUsers(f)
f.delete()
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.