GORM 那傻逼文档真是傻逼妈妈给傻逼儿子开门,傻逼到家了
Many to Many 会在两个 model 中添加一张连接表。
例如,您的应用包含了 user 和 language,且一个 user 可以说多种 language,多个 user 也可以说一种 language。
// User 拥有并属于多种 language,`user_languages` 是连接表
type User struct {
gorm.Model
Languages []Language `gorm:"many2many:user_languages;"`
}
type Language struct {
gorm.Model
Name string
}
当使用 GORM 的 AutoMigrate
为 User
创建表时,GORM 会自动创建连接表
反向引用
// User 拥有并属于多种 language,`user_languages` 是连接表
type User struct {
gorm.Model
Languages []*Language `gorm:"many2many:user_languages;"`
}
type Language struct {
gorm.Model
Name string
Users []*User `gorm:"many2many:user_languages;"`
}
在这个例子中,我们有两个实体:User
和 Language
。一个 User
可以说多种 Language
,而多个 User
也可以说同一种 Language
。在这种情况下,我们使用了 GORM 的 "多对多" 关联。通过在实体结构中添加 many2many
标签,我们可以定义这种关系。
当使用 GORM 的 AutoMigrate
为 User
和 Language
创建表时,GORM 会自动创建一个名为 user_languages
的连接表。这个表将记录 User
和 Language
之间的关系。连接表的结构如下:
user_languages
表:
字段名 | 字段类型 | 示例值 |
---|---|---|
user_id | int | 1 |
language_id | int | 2 |
在上面的示例中,我们在 Language
结构中添加了一个反向引用 Users
,它指向与该 Language
关联的所有 User
。这样,我们可以在查询时方便地获取与特定语言关联的所有用户。
例如,如果你想获取说英语(ID 为 1)的所有用户,你可以这样做:
var english Language
db.Preload("Users").Find(&english, "id = ?", 1)
这个查询将预加载与 english
关联的所有用户。你可以通过访问 english.Users
来获取它们。通过添加反向引用,你可以更轻松地在 User
和 Language
之间导航和查询相关数据。
如果不加反向引用呢?
如果不在 Language
结构中加入反向引用,那么你将不能直接从 Language
结构预加载与之关联的所有 User
。但是,你仍然可以通过编写稍微复杂的查询来获取同样的信息。
例如,在不使用反向引用的情况下,要获取说英语(ID 为 1)的所有用户,你可以使用以下查询:
var users []User
db.Joins("JOIN user_languages ON user_languages.user_id = users.id").
Where("user_languages.language_id = ?", 1).
Find(&users)
这个查询会执行一个连接操作(JOIN),通过 user_languages
表来关联 User
和 Language
。然后,它会过滤出说英语(language_id
为 1)的用户。虽然这样的查询稍微复杂一些,但在不使用反向引用的情况下,仍然可以获取所需的数据。
查询方法
// 检索 User 列表并预加载 Language func GetAllUsers(db *gorm.DB) ([]User, error) { var users []User err := db.Model(&User{}).Preload("Languages").Find(&users).Error return users, err } // 检索 Language 列表并预加载 User func GetAllLanguages(db *gorm.DB) ([]Language, error) { var languages []Language err := db.Model(&Language{}).Preload("Users").Find(&languages).Error return languages, err }
新增方法
要修改多对多关系,您可以使用 Association
函数。例如,要为名为 “Alice” 的用户添加两种语言 “English” 和 “Spanish”,您可以这样做:
var user User db.Where("name = ?", "Alice").First(&user) english := Language{Name: "English"} spanish := Language{Name: "Spanish"} db.Model(&user).Association("Languages").Append([]Language{english, spanish})
上面的代码会在数据库中查找名为 “Alice” 的用户。如果找到了,它会将查询结果保存到 user
变量中。然后,它会在数据库中查找名为 “English” 和 “Spanish” 的语言。如果找到了,它会在连接表 user_languages
中插入两条新记录来表示关系。
更新方法
要更新多对多关系,您可以使用 Association
函数。例如,要将名为 “Alice” 的用户的语言 “English” 更改为 “Chinese”,您可以这样做:
var user User db.Where("name = ?", "Alice").First(&user) english := Language{Name: "English"} chinese := Language{Name: "Chinese"} db.Model(&user).Association("Languages").Replace([]Language{english}, []Language{chinese})
上面的代码会在数据库中查找名为 “Alice” 的用户。如果找到了,它会将查询结果保存到 user
变量中。然后,它会在连接表 user_languages
中删除与用户 “Alice” 和语言 “English” 相关联的记录,并插入一条新记录来表示用户 “Alice” 和语言 “Chinese” 的关系。
清空多对多关系
要清空多对多关系,您可以使用 Association
函数。例如,要清空名为 “Alice” 的用户的所有语言,您可以这样做:
var user User db.Where("name = ?", "Alice").First(&user) db.Model(&user).Association("Languages").Clear()
上面的代码会在数据库中查找名为 “Alice” 的用户。如果找到了,它会将查询结果保存到 user
变量中。然后,它会在连接表 user_languages
中删除与用户 “Alice” 相关联的所有记录。