需要注意,引入包: gorm.io/gorm
而不是 github.com/jinzhu/gorm
连接数据库
自动生成表
var models []any
// 方式一: 会自动同步添加、更新字段,不会删除
db.AutoMigrate(...models)
// 方式二
for _, value := range models {
hasTable := db.HasTable(value)
if !hasTable {
db.CreateTable(value)
}
refType := reflect.TypeOf(value)
if refType.Kind() == reflect.Pointer { // 引用类型
refType = refType.Elem() // 取引用实体
}
println("reflact.Type", refType.Name(), refType.PkgPath(), refType.Kind())
}
设置日志
db.LogMode(true)
模型定义
重置表名
func (Model) TableName() string {
return "new_table_name"
}
数据插入前置操作
func (Model) BeforeCreate(db *gorm.DB) error {
// 插入数据前调用
return nil
}
查询数据
- Take
- Find
- Scan
- Where
- Distinct
- Not
- Order
- Group
- Limit
- Offset
插入数据
更新数据
- Update
- Set
高级查询
一对多
- Belongs To:属于
- Has One:拥有
表模型结构
type User struct {
ID uint `gorm:"size:4"`
Name string `gorm:"size:8"`
Articles []Article // 用户拥有的文章
}
type Article struct {
ID uint `gorm:"size:4"`
Title string `gorm:"size:16"`
UserID uint `gorm:"size:4"` // 属于, 注意这里的类型要和User.ID的类型保持一致
User User
}
默认外键名就是关联表明+ID名
后置添加关联
给用户绑定文章
var user User
DB.Take(&user, 1)
var article Article
DB.Take(&article, 1)
DB.Model(&user).Association("Articles").Append(&article)
给文章绑定用户
var user User
DB.Take(&user, 1)
var article Article
DB.Take(&article, 1)
DB.Model(&article).Association("User").Append(&user)
预加载
嵌套预加载
var user User
DB.Debug().Preload("Articles.User").Take(&user)
带条件的预加载
var user User
DB.Debug().Preload("Articles", "id = ?", 1).Take(&user)
自定义预加载
var user User
DB.Debug().Preload("Articles", func(db *gorm.DB) *gorm.DB {
return db.Where("id in ?", []int{1, 2})
}).Take(&user)
删除
级联删除
删除用户,与用户关联的文章也会删除
var user User
DB.Take(&user, 1)
DB.Select("Articles").Delete(&user)
清除外键关系
删除用户,与将用户关联的文章外键置为null
var user User
DB.Preload("Articles").Take(&user, 1)
DB.Model(&user).Association("Articles").Delete(&user.Articles)
一对一
一对一很多地方跟一对多操作是相同或类似的
表模型结构
type User struct {
ID uint `gorm:"size:4"`
Name string `gorm:"size:8"`
UserInfo UserInfo // 通过UserInfo可以拿到用户详情信息
UserPwd UserPwd // 用户密码表
}
type UserInfo struct {
ID uint
UserID uint `gorm:"size:4"`
User *User
CardNo string
}
多对多
表模型结构
type Tag struct {
ID uint
Name string
Articles []Article `gorm:"many2many:article_tags;"`
}
type Article struct {
ID uint
Title string
Tags []Tag `gorm:"many2many:article_tags;"`
}
添加
DB.Create(&Article{
Title: "Gorm基础",
Tags: []Tag{
{Name: "gorm"},
{Name: "golang"},
},
})
更新
移除文章标签
var article Article
DB.Preload("Tags").Take(&article, 1)
DB.Model(&article).Association("Tags").Delete(&article.Tags)
更新文章标签
var tags []Tag
DB.Find(&tags, []int{1,2,3}) // 实际可能是传入tag ids
var article Article
DB.Preload("Tags").Take(&article, 1)
DB.Model(&article).Association("Tags").Replace(&tags)
删除
var article Article
DB.Preload("Tags").Take(&article, 1)
DB.Model(&article).Association("Tags").Delete(article.Tags)
自定义连接表
需要添加多余字段时会用到
type ArticleTags struct {
ArticleId uint `gorm:"primaryKey"`
TagId uint `gorm:"primaryKey"`
CreatedAt time.Time `json:"created_at"`
}
// init
DB.SetupJoinTable(&Article{}, "Tags", &ArticleTags{})
DB.SetupJoinTable(&Tag{}, "Articles", &ArticleTags{})
添加文章,关联已有Tag
var tags []Tag
DB.Find(tags, uint[]{1, 2})
DB.Create(&Article{
Title: "gorm基础",
Tags: tags,
}) // 这里只有在使用SetupJoinTable后才会更新,否则为新增
自定义连接表主键
type ArticleModel struct {
ID uint
Title string
Tags []TagModel `gorm:"many2many:article_tags;joinForeignKey:ArticleID;JoinReferences:TagID"`
}
type TagModel struct {
ID uint
Name string
Articles []ArticleModel `gorm:"many2many:article_tags;joinForeignKey:TagID;JoinReferences:ArticleID"`
}
type ArticleTagModel struct {
ArticleId uint `gorm:"primaryKey"` // 默认应该是 表名 + 字段名 = ArticleModelId
TagId uint `gorm:"primaryKey"` // 默认应该是 TagModelId
CreatedAt time.Time `json:"created_at"`
}
func init() {
DB.SetupJoinTable(&ArticleModel{}, "Tags", &ArticleTagModel{})
DB.SetupJoinTable(&TagModel{}, "Articles", &ArticleTagModel{})
}
查询多对多连接表
type UserMode struct {
ID uint
Name string
Collects []ArticleModel `gorm:"many2many:user_collect_model;joinForeignKey:UserID;JoinReferences:ArticleID"`
}
type ArticleModel struct {
ID uint
Title string
// 这里也可以反向引用,根据文章查找哪些用户收藏了
}
type UserCollectModel struct {
UserId uint `gorm:"primaryKey"` // 默认应该是 UserModelId
UserModel UserModel `gorm:"foreignKey:UserId"`
ArticleId uint `gorm:"primaryKey"` // 默认应该是 表名 + 字段名 = ArticleModelId
ArticleModel ArticleModel `gorm:"foreignKey:ArticleId"`
CreatedAt time.Time `json:"created_at"`
}
func init() {
DB.SetupJoinTable(&UserModel{}, "Collects", &UserCollectModel{})
err := DB.AutoMigrate(&UserModel{}, &ArticleModel{}, &UserCollectModel{})
fmt.Println(err)
}
根据用户查文章
var userCoolects []UserCollect
DB.Preload("ArticleModel").Preload("UserModel").Find(&userCoolects, 1)
自定义数据类型
JSON
type Info struct {
Status string `json:"status"`
Addr string `json::"addr"`
Age int `json:"age"`
}
func (i *Info) Scan(value any) error {
bytes, ok := value.([]byte)
if !ok {
return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value))
}
err := json.Unmarshal(byte, i)
return err
}
func (i Info) Value() (driver.Value, error) {
return json.Marshal(i)
}
使用
type AutoModel struct {
ID uint
Name string
Info Info `gorm:"type:string"`
}
枚举
type Status int
func (s Status) MarshalJSON() ([]byte, error) {
var result string
switch s {
case Status_Running:
result = "Running"
case Status_Offline:
result = "Offline"
case Status_Except:
result = "Except"
}
return json.Marshal(result)
}
const (
Status_Running Status = 0
Status_Offline Status = 1
Status_Except Status = 2
)
使用
type Host {
ID uint
Status Status `gorm:"size:8" json:"status"`
IP string `json:"ip"`
}
var host Host
DB.Take(&host, 1)
str, _ := json.Marshal(&host)
fmt.Println(string(str))