gorm写入零值问题

作者:matrix 发布时间:2024-10-21 分类:Golang

gorm中如果数据为结构体类型的零值时,不会触发零值更新。

比如当前有表结构体

type OrderTemplate struct {
    ID           int    `gorm:"primaryKey;autoIncrement;column:id" json:"id"`
    InputType    int    `gorm:"not null;default:1;column:input_type" json:"input_type"`       
}

注意:
InputType类型为 int,设置了default为 1

当数据传入 0 ,是 int 类型的默认零值0,会认为你没有传入所以就用default值去填充。如果这里不配置default,系统也就不会写入数据。

解决方案

结构体字段使用非int类型,如 sql.NullInt64,*int指针

简单点建议直接使用指针类型。使用sql.NullInt64类型传入时需要注意设置Valid为 true

sql.NullInt64{
    Int64: 传入值,
    Valid: true, // 表示这个传入值有效,即使它是 0
}

Valid: false 表示传入值无效,即写入默认 Null。

查询或者更新数据的时候也同样会遇到零值问题。

参考:

https://juejin.cn/post/7354940230301483017

GORM中使用虚拟字段

作者:matrix 发布时间:2023-11-30 分类:Golang

使用gorm时,可能需要处理虚拟字段(不在数据库中实际存在的字段)的情况。可以使用结构体tag标签来支持

User结构体模型

type User struct {
    ID    uint    `gorm:"primaryKey;not null"` // 主键ID

    // 虚拟字段
    Isvip int     `gorm:"-;default:0"`         // 是否vip 1是 0否
}

说明:

IsVip字段被标记为 gorm:"-" ,表示虚拟字段。gorm在进行数据库操作(如查询、插入、更新等)时,将不会考虑此字段。同时,可以使用default 标签为其指定默认值。

自定义获取器

自定义一个Get方法 例如,下面的GetIsVip方法会基于用户的VIP状态来返回相应的值:

func (u *User) GetIsVip() int {
    if u.Vip != nil && u.Vip.IsActive == 1 {
        return 1
    }
    return 0
}

应用获取器

在查询User对象时,GORM提供了 AfterFind 方法来自动执行特定逻辑。这在处理虚拟字段时很有用:

// 查询数据时自动赋值字段
func (u *User) AfterFind(tx *gorm.DB) (err error) {
    if u.Vip == nil {
        //TIPS:Association方法手动触发模型关联。如果使用Preload会再次查询User主表,不推荐
        // tx.Preload("Vip").First(&u, u.ID) //不推荐
        tx.Model(u).Association("Vip").Find(&u.Vip)
    }
    u.Isvip = u.GetIsVip() // 手动触发虚拟字段计算

    return
}

说明:

首先检查VIP信息是否已加载。如果未加载,则使用Association方法手动触发加载。之后,我们使用前面定义的GetIsVip方法来计算并设置Isvip字段的值。

注意

使用AfterFind可能会覆盖Isvip字段的默认值(如default:0