如何在 gorm 中创建双向多对多关系
How to create a bidirectional many2many relationship in gorm
根据the doc自相关many2many
如下
type User struct {
gorm.Model
Friends []*User `gorm:"many2many:user_friends"`
}
但我希望能够像这样建模:
type User struct {
gorm.Model
Followings []*User `gorm:"many2many:user_relation"`
Followers []*User `gorm:"many2many:user_relation"`
}
所以下面的过程效果很好。如果 userA
关注 userB
,那么 userB
可以在其关注者中看到 userA
。
type User struct {
gorm.Model
Followings []*User `gorm:"many2many:followings"`
Followers []*User `gorm:"many2many:followers"`
}
它将导致三个 tables:
CREATE TABLE `users` (`id` integer,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,PRIMARY KEY (`id`))
CREATE TABLE `followings` (`user_id` integer,`following_id` integer,PRIMARY KEY (`user_id`,`following_id`),CONSTRAINT `fk_followings_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`),CONSTRAINT `fk_followings_followings` FOREIGN KEY (`following_id`) REFERENCES `users`(`id`))
CREATE TABLE `followers` (`user_id` integer,`follower_id` integer,PRIMARY KEY (`user_id`,`follower_id`),CONSTRAINT `fk_followers_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`),CONSTRAINT `fk_followers_followers` FOREIGN KEY (`follower_id`) REFERENCES `users`(`id`))
更新:
实际上,单个连接 table 也是可能的:
type User struct {
gorm.Model
Name string
Followings []*User `gorm:"many2many:user_relation;joinForeignKey:user_Id;JoinReferences:following_id"`
Followers []*User `gorm:"many2many:user_relation;joinForeignKey:following_id;JoinReferences:user_Id"`
}
已创建 tables:
CREATE TABLE `users` (`id` integer,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,`name` text,PRIMARY KEY (`id`))
CREATE TABLE `user_relations` (`user_id` integer,`following_id` integer,PRIMARY KEY (`user_id`,`following_id`),CONSTRAINT `fk_user_relations_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`),CONSTRAINT `fk_user_relations_followings` FOREIGN KEY (`following_id`) REFERENCES `users`(`id`))
您可以按如下方式使用它:
db.AutoMigrate(&User{})
user1 := User{Name: "John"}
user2 := User{Name: "Tom", Followings: []*User{&user1}}
db.Save(&user2)
var users []User
db.Debug().Preload("Followings").Preload("Followers").Find(&users)
str, _ := yaml.Marshal(&users)
println(string(str))
输出:
- model:
id: 1
createdat: 2020-09-08T22:47:33.910748505+02:00
updatedat: 2020-09-08T22:47:33.910748505+02:00
deletedat:
time: 0001-01-01T00:00:00Z
valid: false
name: Tom
followings:
- model:
id: 2
createdat: 2020-09-08T22:47:33.910906472+02:00
updatedat: 2020-09-08T22:47:33.910906472+02:00
deletedat:
time: 0001-01-01T00:00:00Z
valid: false
name: John
followings: []
followers: []
followers: []
- model:
id: 2
createdat: 2020-09-08T22:47:33.910906472+02:00
updatedat: 2020-09-08T22:47:33.910906472+02:00
deletedat:
time: 0001-01-01T00:00:00Z
valid: false
name: John
followings: []
followers:
- model:
id: 1
createdat: 2020-09-08T22:47:33.910748505+02:00
updatedat: 2020-09-08T22:47:33.910748505+02:00
deletedat:
time: 0001-01-01T00:00:00Z
valid: false
name: Tom
followings: []
followers: []
您甚至可以预加载更多关卡 followers-followings:
db.Debug().Preload("Followings").Preload("Followers").Preload("Followings.Followers").Preload("Followings.Followings").Find(&users)
不幸的是,使用 Joins 预加载似乎不起作用。
我是通过这些标签实现的:
type User struct {
gorm.Model
Followings []*User `gorm:"many2many:user_relation;foreignKey:ID;joinForeignKey:UserA;References:ID;joinReferences:UserB"`
Followers []*User `gorm:"many2many:user_relation;foreignKey:ID;joinForeignKey:UserB;References:ID;joinReferences:UserA"`
}
根据the doc自相关many2many
如下
type User struct {
gorm.Model
Friends []*User `gorm:"many2many:user_friends"`
}
但我希望能够像这样建模:
type User struct {
gorm.Model
Followings []*User `gorm:"many2many:user_relation"`
Followers []*User `gorm:"many2many:user_relation"`
}
所以下面的过程效果很好。如果 userA
关注 userB
,那么 userB
可以在其关注者中看到 userA
。
type User struct {
gorm.Model
Followings []*User `gorm:"many2many:followings"`
Followers []*User `gorm:"many2many:followers"`
}
它将导致三个 tables:
CREATE TABLE `users` (`id` integer,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,PRIMARY KEY (`id`))
CREATE TABLE `followings` (`user_id` integer,`following_id` integer,PRIMARY KEY (`user_id`,`following_id`),CONSTRAINT `fk_followings_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`),CONSTRAINT `fk_followings_followings` FOREIGN KEY (`following_id`) REFERENCES `users`(`id`))
CREATE TABLE `followers` (`user_id` integer,`follower_id` integer,PRIMARY KEY (`user_id`,`follower_id`),CONSTRAINT `fk_followers_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`),CONSTRAINT `fk_followers_followers` FOREIGN KEY (`follower_id`) REFERENCES `users`(`id`))
更新:
实际上,单个连接 table 也是可能的:
type User struct {
gorm.Model
Name string
Followings []*User `gorm:"many2many:user_relation;joinForeignKey:user_Id;JoinReferences:following_id"`
Followers []*User `gorm:"many2many:user_relation;joinForeignKey:following_id;JoinReferences:user_Id"`
}
已创建 tables:
CREATE TABLE `users` (`id` integer,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,`name` text,PRIMARY KEY (`id`))
CREATE TABLE `user_relations` (`user_id` integer,`following_id` integer,PRIMARY KEY (`user_id`,`following_id`),CONSTRAINT `fk_user_relations_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`),CONSTRAINT `fk_user_relations_followings` FOREIGN KEY (`following_id`) REFERENCES `users`(`id`))
您可以按如下方式使用它:
db.AutoMigrate(&User{})
user1 := User{Name: "John"}
user2 := User{Name: "Tom", Followings: []*User{&user1}}
db.Save(&user2)
var users []User
db.Debug().Preload("Followings").Preload("Followers").Find(&users)
str, _ := yaml.Marshal(&users)
println(string(str))
输出:
- model:
id: 1
createdat: 2020-09-08T22:47:33.910748505+02:00
updatedat: 2020-09-08T22:47:33.910748505+02:00
deletedat:
time: 0001-01-01T00:00:00Z
valid: false
name: Tom
followings:
- model:
id: 2
createdat: 2020-09-08T22:47:33.910906472+02:00
updatedat: 2020-09-08T22:47:33.910906472+02:00
deletedat:
time: 0001-01-01T00:00:00Z
valid: false
name: John
followings: []
followers: []
followers: []
- model:
id: 2
createdat: 2020-09-08T22:47:33.910906472+02:00
updatedat: 2020-09-08T22:47:33.910906472+02:00
deletedat:
time: 0001-01-01T00:00:00Z
valid: false
name: John
followings: []
followers:
- model:
id: 1
createdat: 2020-09-08T22:47:33.910748505+02:00
updatedat: 2020-09-08T22:47:33.910748505+02:00
deletedat:
time: 0001-01-01T00:00:00Z
valid: false
name: Tom
followings: []
followers: []
您甚至可以预加载更多关卡 followers-followings:
db.Debug().Preload("Followings").Preload("Followers").Preload("Followings.Followers").Preload("Followings.Followings").Find(&users)
不幸的是,使用 Joins 预加载似乎不起作用。
我是通过这些标签实现的:
type User struct {
gorm.Model
Followings []*User `gorm:"many2many:user_relation;foreignKey:ID;joinForeignKey:UserA;References:ID;joinReferences:UserB"`
Followers []*User `gorm:"many2many:user_relation;foreignKey:ID;joinForeignKey:UserB;References:ID;joinReferences:UserA"`
}