gorm更新数据遇到的空值问题

package gorm_tests

import (
    "fmt"
    "github.com/fatih/structs"
    "github.com/go-playground/validator/v10"
    "github.com/stretchr/testify/require"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "testing"
)

// 参考文档:
// Golang结构体校验:https://juejin.cn/post/6900375680358285325
// Golang结构体校验validator库:https://www.cnblogs.com/jiujuan/p/13823864.html

const (
    studentTableName = "student"
)

// Notice 因为要用structs转成的map修改数据库,所以需要structs与gorm标签的值一一对应
type Student struct {
    ID    uint    `gorm:"primaryKey;column:id" structs:"id"`                           // id在数据库中自动递增生成,不用校验
    Name  string  `gorm:"column:name" structs:"name" validate:"required,min=1,max=20"` // 1 <= len <= 20
    Age   uint8   `gorm:"column:age" structs:"age" validate:"required,max=150"`        // 最大150
    Email string  `gorm:"column:email" structs:"email" validate:"required,min=1"`      // 1 <= len Notice required设置后不能传0
    Score float32 `gorm:"column:score" structs:"score" validate:"min=0"`
    Notes string  `gorm:"column:notes" structs:"notes"`
}

func (s Student) TableName() string {
    return studentTableName
}

func genDb() (*gorm.DB, error) {
    dsn := "root:123@tcp(192.168.110.175:3307)/whw?charset=utf8mb4&parseTime=True&loc=Local"
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    fmt.Println("db: ", db)
    return db, err
}

// Updates方法用结构体更新,无法更新为零值
func TestS1(t *testing.T) {
    s1 := Student{
        ID:    1,
        Name:  "rrrr`12",
        Age:   12, // Notice Age设置了validate为required,所以不能传0!传0的话无法通过校验!!
        Email: "22222@qq.com",
        Score: 0,
        Notes: "",
    }

    // validator校验
    va := validator.New()
    errVa := va.Struct(s1)
    if errVa != nil {
        fmt.Println("errVa: ", errVa)
        return
    }

    db, errDB := genDb()
    require.Equal(t, errDB, nil)
    // Notice 注意这里用 .Error
    errUp := db.Table(studentTableName).Where("id = ?", s1.ID).Updates(&s1).Error
    require.Equal(t, errUp, nil)
    // Notice: 运行结束后,Notes值不能改成空字符串!!!Score不能改成0!!!
}

// Updates方法用map更新,但是需要注意,structs转成的map携带所有字段,如果有不想更新的字段需要"过滤"一下
func TestS2(t *testing.T) {
    s1 := Student{
        ID:    1,
        Name:  "naruto",
        Age:   12, // Notice Age设置了validate为required,所以不能传0!传0的话无法通过校验!!
        Email: "22222@qq.com",
        Score: 0,
        Notes: "",
    }

    // validator校验
    va := validator.New()
    errVa := va.Struct(s1)
    if errVa != nil {
        fmt.Println("errVa: ", errVa)
        return
    }

    db, errDB := genDb()
    require.Equal(t, errDB, nil)

    // 结构体先转map
    s1Map := structs.Map(&s1)
    // key都有
    fmt.Println("s1Map: ", s1Map) // map[age:12 email:22222@qq.com id:1 name:naruto notes: score:0]
    // Notice 哪些字段不想跟着更新,过滤一下,模拟实际场景就用id了~
    updateMap := make(map[string]interface{})
    for key := range s1Map {
        // 跟structs标签值对应
        if key == "id" {
            continue
        }
        updateMap[key] = s1Map[key]
    }
    fmt.Println("updateMap: ", updateMap) // map[age:12 email:22222@qq.com name:naruto notes: score:0]

    // 使用map更新,可以更新为零值
    // .Error
    errUpdate := db.Table(studentTableName).Where("id = ?", s1.ID).Updates(updateMap).Error
    require.Equal(t, errUpdate, nil)

}

~~~

posted on 2022-12-02 19:55  江湖乄夜雨  阅读(975)  评论(0编辑  收藏  举报