Considering I define a JSONTime type to control the output format of time
type JSONTime time.Time
func (t JSONTime) MarshalJSON() ([]byte, error) {
stamp := fmt.Sprintf(`"%s"`, time.Time(t).Format("2006-01-02 15:04:05"))
return []byte(stamp), nil
}
In the model definition, I cannot set the DeletedAt field type to JSONTime, or soft delete won't work. Since this field won't show to user, the code below is still reasonable. But if you can solve it, it makes OCDers feel better :)
type Role struct {
Id uint `gorm:"primary_key"`
CreatedAt JSONTime
UpdatedAt JSONTime
DeletedAt *time.Time `sql:"index"` //cannot use JSONTime, or soft delete won't work.
Name string
}
Further, with JSONTime, the CreatedAt and UpdatedAt won't save to db, but reading them is ok.
@qjebbs did you solve this? I have the same issue
@mehdy @qjebbs same here :S any workaround or something ?
@BertrandGouny @mehdy use callbacks
add callbacks
// ... init gorm
DB, err = gorm.Open("mysql", "DSN")
// ... handle error
// add callbacks refer: http://gorm.io/docs/write_plugins.html
DB.Callback().Create().After("gorm:update_time_stamp").Register("mark_timestamp_normal", markTimestampNormal)
DB.Callback().Update().After("gorm:update_time_stamp").Register("mark_timestamp_normal", markTimestampNormal)
// ....
func markTimestampNormal(scope *gorm.Scope) {
if createdAtField, ok := scope.FieldByName("CreatedAt"); ok {
createdAtField.IsNormal = true
}
if updatedAtField, ok := scope.FieldByName("UpdatedAt"); ok {
updatedAtField.IsNormal = true
}
}
alias
// alias
type Timestamp time.Time
// UnmarshalParam echo api @see https://echo.labstack.com/guide/request
func (t *Timestamp) UnmarshalParam(src string) error {
if src != "" {
m, err := strconv.ParseInt(src, 10, 64)
if err != nil {
return err
}
ts := time.Unix(0, m*int64(time.Millisecond))
*t = Timestamp(ts)
}
return nil
}
// MarshalJSON echo api json response
func (t *Timestamp) MarshalJSON() ([]byte, error) {
if t != nil {
ts := time.Time(*t)
return []byte(fmt.Sprintf(`"%d"`, ts.UnixNano()/int64(time.Millisecond))), nil
}
return nil, nil
}
// for sql log, print readable format
func (t Timestamp) String() string {
ts := time.Time(t)
return ts.Format(time.RFC3339)
}
// insert into database conversion
func (t Timestamp) Value() (driver.Value, error) {
return time.Time(t), nil
}
// read from database conversion
func (t *Timestamp) Scan(src interface{}) error {
if val, ok := src.(time.Time); ok {
*t = Timestamp(val)
}
return nil
}
define model, should work
type App struct {
Id uint32 `json:"id,string"`
AppKey string `json:"appKey" validate:"required"`
AppSecret string `json:"appSecret" validate:"required"`
AppName string `json:"appName" validate:"required"`
CreatedAt Timestamp `json:"createdAt"`
UpdatedAt *Timestamp `json:"updatedAt"`
}
@yinheli thanks!
@yinheli
你好,根据你的方法,在我的 mysql 中,创建出来的字段为 bigint 类型。但现在我需要为 time.Time 类型取别名,同时保证字段在数据库中为 datetime 类型。我可以这样做吗?我应该怎么做?
@yinheli
你好,根据你的方法,在我的 mysql 中,创建出来的字段为 bigint 类型。但现在我需要为 time.Time 类型取别名,同时保证字段在数据库中为 datetime 类型。我可以这样做吗?我应该怎么做?
一样的思路, 关键是实现 func Value() (driver.Value, error) func Scan(src interface{}) error 方法
@yinheli 您好,我也是用你这个办法,但是创建出来的数据库类型和 @youguanxinqing 一样,是bigint类型,请问是哪里搞错了吗?除非手动加上gorm:"type:datetime"
Most helpful comment
@BertrandGouny @mehdy use callbacks