Skip to content

Gorm 查询输出数据优化

November 27, 2024
4 min read
652 words

time.Time类型数据

问题

使用gorm时,定义与时间相关的字段时,一般定义的类型为time.Time

go
type CommonBaseModel struct {
	ID        string `gorm:"primary_key" json:"userId"`
	CreatedAt *LocalTime			`json:"created_at,omitempty"`
	UpdatedAt *LocalTime      `json:"updated_at,omitempty"`
	DeletedAt *gorm.DeletedAt `gorm:"index" json:"deleted_at,omitempty"`
}

当在执行查询操作时,获取的值为ISO 8601格式,格式为2021-06-15T10:14:02.973528+08:00

具体含义:

  • 日期格式:YYYY-MM-DD 2021-06-15
    • YYYY表示四位数的年份
    • MM表示两位数的月份
    • DD表示两位数的日期
  • 时间格式:hh:mm:ss.ms 10:14:02.973528
    • hh表示两位数的小时
    • mm表示两位数的分钟
    • ss表示两位数的秒
    • ms表示微秒
  • 日期和时间结合:YYYY-MM-DDThh:mm:ss.ms T
    • 使用字母’T’来分隔日期和时间
  • 时区 +08:00

解决办法

version

gorm.io/gorm v1.25.12
gorm.io/driver/mysql v1.5.7

使用自定义数据类型解决

1、定义自定义的类型

go
type LocalTime time.Time

2、重写MarshalJSON方法来实现数据解析

go
func (t *LocalTime) MarshalJSON() ([]byte, error) {
	tTime := time.Time(*t)
	return []byte(fmt.Sprintf("\"%v\"", tTime.Format("2006-01-02 15:04:05"))), nil
}

3、实现Scanner和Valuer接口

go
func (t *LocalTime) Value() (driver.Value, error) {
    var zeroTime time.Time
    tlt := time.Time(t)
    //判断给定时间是否和默认零时间的时间戳相同
    if tlt.UnixNano() == zeroTime.UnixNano() {
        return nil, nil
    }
    return tlt, nil
}

func (t *LocalTime) Scan(v interface{}) error {
    if value, ok := v.(time.Time); ok {
        *t = LocalTime(value)
        return nil
    }
    return fmt.Errorf("can not convert %v to timestamp", v)
}

排除某些字段

gorm查询时,通过Select方法选择特定字段进行数据查询,当数据字段很多时,仅需要排除某个或几个字段时,使用Omit方法进行字段的排除 但数据的数据仍有字段名称只是值为空,可以使用omitempty空值省略,排除字段。

具体代码

UserModel

go
type User struct {
	CommonBaseModel `gorm:"embedded"`
	Name            string     `gorm:"comment:用户名" json:"name"`
	PassWord        string     `gorm:"comment:密码" json:"password,omitempty"`
	Avatar          string     `gorm:"comment:头像" json:"avatar"`
	Gender          string     `gorm:"column:gender;default:male;type:varchar(6);comment:male表示男,female表示女" json:"gender"` //gorm为数据库字段约束
	Phone           string     `valid:"matches(^1[3-9]{1}\\d{9}$)" json:"phone"`                                           //valid为条件约束
	Email           string     `valid:"email" json:"email"`
	Identity        string     `gorm:"comment:用户身份" json:"identity,omitempty"`
	ClientIp        string     `valid:"ipv4" gorm:"comment:设备IP" json:"client_ip,omitempty"`
	ClientPort      string     `gorm:"comment:设备端口" json:"client_port,omitempty"`
	Salt            string     `gorm:"comment:用户密码MD5盐值" json:"salt,omitempty"`
	LoginTime       *time.Time `gorm:"column:login_time" json:"login_time,omitempty"`
	HeartBeatTime   *time.Time `gorm:"column:heart_beat_time" json:"heart_beat_time"`
	LoginOutTime    *time.Time `gorm:"column:login_out_time" json:"login_out_time,omitempty"`
	IsLoginOut      bool       `json:"is_login_out"`
	DeviceInfo      string     `json:"device_info"` //登录设备
}

func (table *User) UserTableName() string {
	return "users"
}

获取列表数据

go
// GetUserList 获取用户列表
func GetUserList() ([]*models.User, error) {
	var list []*models.User
	if tx := global.DB.Omit("Salt", "Identity",
		"PassWord", "ClientIp", "ClientPort", "UpdatedAt", "DeletedAt").Find(&list); tx.Error != nil {
		if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, tx.Error
	}
	return list, nil
}

参考

Go的省略符 omitempty和 - 两种方式详解