Your Question

使用map[string]interface{}创建数据时, BeforeCreate 等Hook没有生效,测试代码如下:

package main

import (
    "context"

    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
    "gorm.io/gorm/logger"
)

type User struct {
    gorm.Model
    Username string
    Nickname string
    Age int
}

func (*User) TableName() string {
    return "users"
}

func (*User) BeforeCreate(tx *gorm.DB) error {
    // 这里没有被hook
    return nil
}

func main() {
    db, _ := gorm.Open(sqlite.Open("test.db"), &gorm.Config{
        Logger: logger.Default.LogMode(logger.Info),
    })

    _ = db.Migrator().AutoMigrate(&User{})

    _ = db.Model(&User{}).Create(map[string]interface{}{
        "username": "test",
        "nickname": "test",
        "age": 1
    })
}

The document you expected this should be explained

Expected answer

使用 map[string]interface{} 类型创建时,BeforeCreate callbacks 的 db.Statement.Schema 为 map[string]interface{} 类型,
断言 BeforeCreateInterface 时失败

Comment From: urionz

callMethod() 是否可以增加map case ?
if called := fc(db.Statement.ReflectValue.Interface(), tx); !called {
switch db.Statement.ReflectValue.Kind() {
    case reflect.Slice, reflect.Array:
    case reflect.Struct:
    case reflect.Map:
        // 解决使用map create问题
        fc(db.Statement.Model, tx)
}

Comment From: jinzhu

the Model value is an empty struct, doesn't sounds reasonable to invoke its hooks method?

Comment From: urionz

实际上我是想拿到create时Statement.Dest数据用来处理一些业务,这时并不需要关心model是否是空struct。目前我只能replace Hook去解决