go version)?go version go1.9.1 windows/amd64
PostgreSQL 9.4/9.5
Need to runnable with GORM's docker compose config or please provides your config.
package main
import (
"fmt"
"time"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres"
)
var db *gorm.DB
func init() {
var err error
db, err = gorm.Open("postgres", "user=gorm password=gorm DB.name=gorm port=9920 sslmode=disable")
if err != nil {
panic(err)
}
db.LogMode(true)
}
type Model struct {
ID uint `gorm:"primary_key"`
//Created_at an updated_at are of type int because we will save time in UNIX timestamp format
CreatedAt int
UpdatedAt int
}
//BeforeUpdate is a hook to set the created_at column to UNIX timestamp int.
func (m *Model) BeforeUpdate(scope *gorm.Scope) error {
scope.SetColumn("UpdatedAt", int(time.Now().Unix()))
return nil
}
//BeforeCreate is a hook to set the created_at column to UNIX timestamp int.
func (m *Model) BeforeCreate(scope *gorm.Scope) error {
scope.SetColumn("CreatedAt", int(time.Now().Unix()))
return nil
}
type User struct {
Model
Name string
}
func main() {
oUser := User{
Name: "Cool Name",
} //this is the original user
db.Create(&oUser)
user := User{
Name: "New Name",
}
db.Where("id = ?", 1).First(&oUser)
err := db.Debug().Model(&oUser).Updates(user).Error
if err != nil {
fmt.Println("failed")
} else {
fmt.Println("success")
}
}
The issue is that UpdatedAt column is ALWAYS set to time.Time no matter what.
why don't use gorm.Model, see the doc
and you should use the real column name updated_at or created_at.
check your database's column real name.
I have created my own Model because:
The real names are fine, it just doesn't accept changing the updated_at column from timestamp to int64
@SAFAD I'm running into the same problem with updated_at and deleted_at. Did you find a solution?
@SAFAD Do you find a solution ? I'm facing to the same problem.
@mooncool I ended up creating my own model struct and specifying my own hooks for the timestamps. Note - I left deletedAt as is because I don't care so much that that value is int64, and I didn't want to mess w/ gorm's default indexing/filtering by it.
type Model struct {
ID uint `gorm:"primary_key" json:"id"`
CreatedAt int64 `json:"createdAt"`
UpdatedAt int64 `json:"updatedAt"`
DeletedAt *time.Time `sql:"index" json:"deletedAt"`
}
func (m *Model) BeforeUpdate(scope *gorm.Scope) error {
scope.SetColumn("UpdatedAt", time.Now().Unix())
return nil
}
func (m *Model) BeforeCreate(scope *gorm.Scope) error {
if m.UpdatedAt == 0 {
scope.SetColumn("UpdatedAt", time.Now().Unix())
}
scope.SetColumn("CreatedAt", time.Now().Unix())
return nil
}
@mooncool I ended up creating my own model struct and specifying my own hooks for the timestamps. Note - I left deletedAt as is because I don't care so much that that value is int64, and I didn't want to mess w/ gorm's default indexing/filtering by it.
type Model struct { ID uint `gorm:"primary_key" json:"id"` CreatedAt int64 `json:"createdAt"` UpdatedAt int64 `json:"updatedAt"` DeletedAt *time.Time `sql:"index" json:"deletedAt"` } func (m *Model) BeforeUpdate(scope *gorm.Scope) error { scope.SetColumn("UpdatedAt", time.Now().Unix()) return nil } func (m *Model) BeforeCreate(scope *gorm.Scope) error { if m.UpdatedAt == 0 { scope.SetColumn("UpdatedAt", time.Now().Unix()) } scope.SetColumn("CreatedAt", time.Now().Unix()) return nil }
@inoda Many thanks!
Can we close this? Seems like @inoda has a good solution.
use own model struct, why create is ok and update,delete failed?
type Model struct {
ID uint `gorm:"primary_key"`
CreatedAt int64
UpdatedAt int64
DeletedAt *int64
}
func (m *Model) BeforeUpdate(scope *gorm.Scope) error {
scope.SetColumn("UpdatedAt", time.Now().Unix())
return nil
}
func (m *Model) BeforeCreate(scope *gorm.Scope) error {
if m.UpdatedAt == 0 {
scope.SetColumn("UpdatedAt", time.Now().Unix())
}
scope.SetColumn("CreatedAt", time.Now().Unix())
return nil
}
func (m *Model) BeforeDelete(scope *gorm.Scope) error {
scope.SetColumn("DeletedAt", time.Now().Unix())
return nil
}
...
u:=User{Name:"ad"}
db.Create(&u)
db.Model(&u).Update("name", "hello")
db.Delete(&u)
log:
(/home/chen/tmpfs/db.go:100)
[2019-05-15 11:09:13] [0.51ms] INSERT INTO "users" ("created_at","updated_at","deleted_at","name") VALUES ('1557889753','1557889753',NULL,'ad') RETURNING "users"."id"
(/home/chen/tmpfs/db.go:102)
[2019-05-15 11:09:13] pq: æ— æ•ˆçš„æ•´æ•°ç±»åž‹è¾“å…¥è¯æ³•: "2019-05-15T11:09:13.17873335+08:00"
(/home/chen/tmpfs/db.go:102)
[2019-05-15 11:09:13] [0.52ms] UPDATE "users" SET "name" = 'hello', "updated_at" = '2019-05-15 11:09:13' WHERE "users"."deleted_at" IS NULL AND "users"."id" = '6'
(/home/chen/tmpfs/db.go:106)
[2019-05-15 11:09:13] pq: æ— æ•ˆçš„æ•´æ•°ç±»åž‹è¾“å…¥è¯æ³•: "2019-05-15T11:09:13.179478181+08:00"
(/home/chen/tmpfs/db.go:106)
[2019-05-15 11:09:13] [0.40ms] UPDATE "users" SET "deleted_at"='2019-05-15 11:09:13' WHERE "users"."deleted_at" IS NULL AND "users"."id" = '6'
May i replace gorm's default callback func?
db.Callback().Create().Replace("gorm:update_time_stamp", updateTimeStampForCreateCallback)
db.Callback().Update().Replace("gorm:update_time_stamp", updateTimeStampForUpdateCallback)
db.Callback().Delete().Replace("gorm:delete", deleteCallback)
@meilihao, that works! I just replace the callback functions, thanks! 🥇
func CreateConnection(c config.Configuration) (*gorm.DB, error) {
connectionUri := fmt.Sprintf(
"%s:%s@(%s)/%s?charset=utf8&parseTime=True&loc=Local",
c.Database.Username,
c.Database.Password,
c.Database.Host,
c.Database.Database,
)
db, err := gorm.Open("mysql", connectionUri)
if err != nil {
log.Fatalf("error open connection: %s", err)
return nil, err
}
db.Callback().Create().Replace("gorm:update_time_stamp", updateTimeStampForCreateCallback)
db.Callback().Update().Replace("gorm:update_time_stamp", updateTimeStampForUpdateCallback)
return db, nil
}
func updateTimeStampForCreateCallback(scope *gorm.Scope) {
if !scope.HasError() {
now := time.Now().UTC().Unix()
if createdAtField, ok := scope.FieldByName("CreatedAt"); ok {
if createdAtField.IsBlank {
createdAtField.Set(now)
}
}
}
}
func updateTimeStampForUpdateCallback(scope *gorm.Scope) {
if _, ok := scope.Get("gorm:update_column"); !ok {
now := time.Now().UTC().Unix()
scope.SetColumn("UpdatedAt", now)
}
}
Most helpful comment
@meilihao, that works! I just replace the callback functions, thanks! 🥇