Golang Go语言中 新手求助,在 Gorm 的 Callback 里面怎样获取 gin.Context?
我想做的是,每次创建数据,自动插入当前用户 ID 。
我在中间件里面设置了当前登录用户 ID:
c.Set("uid", 1)
在初始化 Gorm 连接的时候,注册了 Callback 回调:
DB.Callback().Create().Before("gorm:before_create").Register("beforeCreateCallback", beforeCreateCallback)
func beforeCreateCallback(db *gorm.DB) {
userID := 获取 gin.Context 里的内容
if _, ok := db.Statement.Schema.FieldsByName["user_id"]; ok {
db.Statement.SetColumn("user_id", userID)
}
}
我想的是定义一个全局变量,在中间件设置完 uid 后,把 gin.Context 赋值给全局变量,请问这样设置有没有什么问题,或者有什么更好的获取方式?
Golang Go语言中 新手求助,在 Gorm 的 Callback 里面怎样获取 gin.Context?
更多关于Golang Go语言中 新手求助,在 Gorm 的 Callback 里面怎样获取 gin.Context?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
同样是新手,没太理解你这操作
更多关于Golang Go语言中 新手求助,在 Gorm 的 Callback 里面怎样获取 gin.Context?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
https://gorm.io/docs/context.html#Context-in-Hooks-x2F-Callbacks
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
ctx := tx.Statement.Context
// …
return
}
我之前有在中间件里面设置,但在 Callback 里面拿到的是 nilGO<br>DB.WithContext(context.WithValue(context.Background(), constants.ContextKey{}, <a target="_blank" href="http://userModel.ID" rel="nofollow noopener">userModel.ID</a>))<br>
GO<br>uid := DB.Statement.Context.Value(constants.ContextKey{})<br>
package main
import (
“log”
“github.com/gin-gonic/gin”
“gorm.io/driver/mysql”
“gorm.io/gorm”
)
type User struct {
gorm.Model
Name string
Email string
}
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
if u.Email == “” {
ctx := tx.Statement.Context
if v, ok := ctx.Value(“Email”).(string); ok {
u.Email = v
}
}
return
}
func main() {
// 初始化 Gin 路由器实例
r := gin.Default()
// 初始化 Gorm 数据库连接
dsn := “root:root@tcp(127.0.0.1:3306)/gorm-example?charset=utf8mb4&parseTime=True&loc=Local”
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic(“failed to connect database”)
}
// 自动迁移模型结构体到数据库表
db.AutoMigrate(&User{})
// 创建处理程序函数
createUser := func(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(400, gin.H{“error”: err.Error()})
return
}
log.Println(“Email:”, c.GetString(“Email”))
db.WithContext©.Create(&user)
c.JSON(200, user)
}
// 自定义中间件,设置 example 变量为 123
r.Use(func(c *gin.Context) {
c.Set(“Email”, “[email protected]”)
c.Next()
})
// 在路由器实例中注册处理程序函数
r.POST("/users", createUser)
// 启动 Gin 服务器,监听 HTTP 请求
r.Run(":8080")
}
我试了一下,这样可以,你对照着看下呢
DB.Callback().Create().Before(“gorm:before_create”).Register(“beforeCreateCallback”, beforeCreateCallback©)
func beforeCreateCallback(c *gin.Context) func(db *gorm.DB) {
return func(db *gorm.DB) {
userID := c.Get(“xxx”)
if _, ok := db.Statement.Schema.FieldsByName[“user_id”]; ok {
db.Statement.SetColumn(“user_id”, userID)
}
}
}
这样确实是可以的,但我不可能每个模型都写一个 BeforeCreate 去设置
调 beforeCreateCallback 这个方法的 c 没有啊,这个回调是在数据库初始化的时候就注册了,我现在是通过定义一个全局变量保存 gin.Context 来实现,就是不知道后面有没有坑
不能。直接放到 user 对象里不好么
把 gin.Context 赋值给全局变量 !
WTF???
查了一下,确实不能放全局,只有重新找其它方式实现
老老实实一个字段一个字段写,没多大工作量,可维护性高很多。
你这里逻辑就有问题,数据库初始化怎么可以和用户 id 绑定呢?用户 id 是数据库查询的条件之一,是具体业务时候添加的条件。
多层调用或多模块间传递变量,又不想老老实实写接口参数,投机的方案就是用全局变量。
当然,为了保证调用上下文的一致性,可以根据逻辑作用域不同,把全局变量分成:全局进程变量、全局线程变量、全局协程变量。
这里,全局协程变量,顾名思义,保证同协程内全局访问到同一个变量,又防止多协程间的访问冲突,当协程结束了,对应的全局协程变量也就回收了。
你可以把 gin.Context 赋值给全局协程变量,前提是得保证用到的地方是同协程内调用,注意下这里的回调会不会切换协程了。
这个投机方案,不知道是否对你有用。
要不设置值用 gin 的 c.Set(“Email”, “123”) 取值可以直接用 db.Statement.Context.(“Email”).(string) 因为 gin 的 context 是自己的实现的,gin 的 ContextWithFallback 参数默认 false ,会直接返回 nil