Golang中gorm如何避免在BindJson时转换ID字段
Golang中gorm如何避免在BindJson时转换ID字段
我正在使用以下结构体,并且不希望GORM因ID主键重复而报错。因此,我尝试了以下方法来在创建方法中忽略ID字段。即,我创建了另一个专门用于创建的结构体,GORM成功地忽略了传入的ID值。但我需要获取新创建记录的ID。我本以为GORM会将其放入GetID字段,但它并没有在其中放入任何ID。
上述方法的问题:我无法知道新创建记录的ID。如果我能以某种方式知道,我会在完整的用户结构体中获取该记录,并在响应中返回给用户,但这并没有发生。
问题:我试图在创建时忽略传入的ID。似乎有两种可能的解决方案:要么让GORM在创建时忽略传入的ID,并在字段中返回新的ID;要么让Gin上下文的BindJson忽略该值,不将其绑定到用户结构体。任何帮助都将不胜感激。谢谢。
type UserBase struct {
ID uint `gorm:"primary_key"`
Email string `validate:"required,email"`
Password string
LanguageId int16
}
type UserCreateUpdate struct {
UserBase
ID uint `gorm:"-",json:"id"`
GetID uint `gorm:"column:id",json:"id"`
// Language language_schema.Language `json:",omitempty"`
}
type User struct {
UserBase
CreatedAt time.Time
UpdatedAt *time.Time // As it can be null thats why the pointer
Language language_schema.Language `json:",omitempty"`
}
// And this is create method
db := schema_utils.GetDB()
var user_create user_schema.UserCreateUpdate
c.BindJSON(&user_create)
validate := user_schema.SchemaValidator(web_api.GetValidator())
if ok, errors := schema_utils.ValidateInputs(user_create, validate); !ok {
web_api.ValidationErrorResponse(errors, c)
} else {
if result := db.Table("users").Create(&user_create); result.Error != nil {
c.JSON(http.StatusUnprocessableEntity, gin.H{"error": result.Error})
} else {
var user user_schema.User
fmt.Println("created")
fmt.Println(user_create.ID)
fmt.Println(user_create.GetID)
db.Where("id = ?", user_create.GetID).Table("users").Preload("Language").First(&user)
c.JSON(200, user)
}
}
更多关于Golang中gorm如何避免在BindJson时转换ID字段的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Golang中gorm如何避免在BindJson时转换ID字段的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Golang中使用GORM时,可以通过以下几种方式避免在BindJson时转换ID字段并正确获取新创建的记录ID:
方法1:使用指针字段和gorm:"-"标签
type UserCreateUpdate struct {
ID *uint `gorm:"-" json:"id,omitempty"` // 使用指针并忽略GORM处理
Email string `validate:"required,email"`
Password string
LanguageId int16
}
// 创建方法
func CreateUser(c *gin.Context) {
db := schema_utils.GetDB()
var userCreate user_schema.UserCreateUpdate
if err := c.BindJSON(&userCreate); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 显式设置ID为nil,确保GORM使用自增ID
userCreate.ID = nil
if result := db.Table("users").Create(&userCreate); result.Error != nil {
c.JSON(http.StatusUnprocessableEntity, gin.H{"error": result.Error})
return
}
// 获取新创建的记录
var user user_schema.User
db.Table("users").Preload("Language").First(&user, userCreate.ID)
c.JSON(200, user)
}
方法2:使用单独的DTO结构体
// 创建专用的DTO结构体,不包含ID字段
type UserCreateDTO struct {
Email string `json:"email" validate:"required,email"`
Password string `json:"password"`
LanguageId int16 `json:"languageId"`
}
// 创建方法
func CreateUser(c *gin.Context) {
db := schema_utils.GetDB()
var userDTO user_schema.UserCreateDTO
if err := c.BindJSON(&userDTO); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 转换为数据库模型
user := user_schema.User{
Email: userDTO.Email,
Password: userDTO.Password,
LanguageId: userDTO.LanguageId,
}
if result := db.Table("users").Create(&user); result.Error != nil {
c.JSON(http.StatusUnprocessableEntity, gin.H{"error": result.Error})
return
}
// 预加载关联数据
db.Table("users").Preload("Language").First(&user, user.ID)
c.JSON(200, user)
}
方法3:使用GORM的Select方法排除字段
type UserCreateUpdate struct {
ID uint `gorm:"primary_key" json:"id,omitempty"`
Email string `validate:"required,email"`
Password string
LanguageId int16
}
// 创建方法
func CreateUser(c *gin.Context) {
db := schema_utils.GetDB()
var userCreate user_schema.UserCreateUpdate
if err := c.BindJSON(&userCreate); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 使用Select排除ID字段
if result := db.Table("users").
Select("Email", "Password", "LanguageId").
Create(&userCreate); result.Error != nil {
c.JSON(http.StatusUnprocessableEntity, gin.H{"error": result.Error})
return
}
// 获取完整记录
var user user_schema.User
db.Table("users").Preload("Language").First(&user, userCreate.ID)
c.JSON(200, user)
}
方法4:使用Omit方法忽略字段
func CreateUser(c *gin.Context) {
db := schema_utils.GetDB()
var userCreate user_schema.UserCreateUpdate
if err := c.BindJSON(&userCreate); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 使用Omit忽略ID字段
if result := db.Table("users").
Omit("ID").
Create(&userCreate); result.Error != nil {
c.JSON(http.StatusUnprocessableEntity, gin.H{"error": result.Error})
return
}
fmt.Println("Created user ID:", userCreate.ID)
var user user_schema.User
db.Table("users").Preload("Language").First(&user, userCreate.ID)
c.JSON(200, user)
}
推荐方案
建议使用方法2(单独的DTO结构体),这是最清晰且符合关注点分离原则的方式:
// DTO用于接收请求
type UserCreateRequest struct {
Email string `json:"email" binding:"required,email"`
Password string `json:"password" binding:"required,min=6"`
LanguageId int16 `json:"languageId"`
}
// 创建方法
func CreateUserHandler(c *gin.Context) {
db := schema_utils.GetDB()
var req user_schema.UserCreateRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 验证
validate := user_schema.SchemaValidator(web_api.GetValidator())
if ok, errors := schema_utils.ValidateInputs(req, validate); !ok {
web_api.ValidationErrorResponse(errors, c)
return
}
// 创建用户记录
user := user_schema.User{
Email: req.Email,
Password: req.Password,
LanguageId: req.LanguageId,
}
if result := db.Create(&user); result.Error != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})
return
}
// 加载关联数据
db.Preload("Language").First(&user, user.ID)
c.JSON(http.StatusCreated, user)
}
这种方法完全避免了ID字段的绑定问题,同时能正确获取GORM自动生成的ID值。

