导读
本套笔记是学习完Gin框架之后的下一个阶段,通过Gin框架我们可以很方便的和前端进行交互,下一步就是和数据库进行交互,这就需要使用GORM。本套笔记就是带你快速上手GORM,学习完这个之后就可以完成大项目的开发了,后续还会进行大项目的讲解开发,制作不易,喜欢的就点个关注吧。
本套课程基于GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.进行讲解,是对这个的补充解释说明。
注意
代码详解大部分是注释的形式给出,请留意代码注释。
GORM介绍
GORM(Go Object Relational Mapping)是一个在 Go 语言中使用的优秀的 ORM(对象关系映射)库。它提供了简单且强大的 API,使开发人员能够轻松地与数据库进行交互
many to many
Many to Many 会在两个 model 中添加一张连接表,将不同表的id连接起来
例如:您的应用包含了 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 会自动创建连接表
完整代码
package main import ( "fmt" "gorm.io/driver/mysql" "gorm.io/gorm" "log" ) type User struct { gorm.Model Languages []Language `gorm:"many2many:user_languages;"` } type Language struct { gorm.Model Name string } func main() { db, err := gorm.Open(mysql.New(mysql.Config{ DSN: "root:Lycdemima1@@tcp(127.0.0.1:3306)/test?charset=utf8&parseTime=True&loc=Local", // DSN data source name DefaultStringSize: 256, // string 类型字段的默认长度 DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持 DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引 DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列 SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置 }), &gorm.Config{}) //连接数据库 // 自动迁移数据库结构 err = db.AutoMigrate(&User{}, &Language{}) if err != nil { log.Fatal(err) } // 创建用户及关联的语言 err = CreateUserWithLanguages(db, "john", "English") if err != nil { log.Fatal(err) } // 查询用户及关联的语言 user, err := GetUserWithLanguages(db, 1) if err != nil { log.Fatal(err) } fmt.Println("User:", user) fmt.Println("Languages:") for _, lang := range user.Languages { fmt.Println(lang) } } func CreateUserWithLanguages(db *gorm.DB, username string, languageName string) error { language := Language{ Name: languageName, } user := User{ Languages: []Language{language}, } result := db.Create(&user) return result.Error } func GetUserWithLanguages(db *gorm.DB, userID uint) (User, error) { var user User result := db.Preload("Languages").First(&user, userID) return user, result.Error }
表关系如图
连接池绑定他们的id
重写外健
对于 many2many
关系,连接表会同时拥有两个模型的外键,例如
type User struct { gorm.Model Languages []Language `gorm:"many2many:user_languages;"` } type Language struct { gorm.Model Name string }
若要重写它们,可以使用标签 foreignKey
、references
、joinforeignKey
、joinReferences
。当然,您不需要使用全部的标签,你可以仅使用其中的一个重写部分的外键、引用。
type User struct { gorm.Model Profiles []Profile `gorm:"many2many:user_profiles;foreignKey:Refer;joinForeignKey:UserReferID;References:UserRefer;joinReferences:ProfileRefer"` Refer uint `gorm:"index:,unique"` } type Profile struct { gorm.Model Name string UserRefer uint `gorm:"index:,unique"` }
自引用
type User struct { gorm.Model Friends []*User `gorm:"many2many:user_friends"` }
会创建连接表:user_friends
走定义连接池
type Person struct { ID int Name string Addresses []Address `gorm:"many2many:person_addressses;"` } type Address struct { ID uint Name string } type PersonAddress struct { PersonID int `gorm:"primaryKey"` AddressID int `gorm:"primaryKey"` CreatedAt time.Time DeletedAt gorm.DeletedAt } func (PersonAddress) BeforeCreate(db *gorm.DB) error { // ... } // 修改 Person 的 Addresses 字段的连接表为 PersonAddress // PersonAddress 必须定义好所需的外键,否则会报错 err := db.SetupJoinTable(&Person{}, "Addresses", &PersonAddress{})