reflect: 在 GORM 的更新操作中调用 reflect.Value.SetString 时对 uint 值的调用

huangapple go评论90阅读模式
英文:

reflect: call of reflect.Value.SetString on uint Value on GORM Updates operation

问题

我正在尝试使用Golang、Gin和GORM构建一个简单的CRUD博客。然而,当我想要更新博客内容时,触发了以下错误:

reflect: call of reflect.Value.SetString on uint Value
/usr/local/go/src/reflect/value.go:223 (0x10bfb25)
        flag.mustBe: panic(&ValueError{methodName(), f.kind()})
/usr/local/go/src/reflect/value.go:2292 (0x10bfaa3)
        Value.SetString: v.mustBe(String)
/Users/sam/go/pkg/mod/gorm.io/gorm@v1.23.5/schema/field.go:771 (0x144fcfc)
        (*Field).setupValuerAndSetter.func11: field.ReflectValueOf(ctx, value).SetString(data)
/Users/sam/go/pkg/mod/gorm.io/gorm@v1.23.5/callbacks/update.go:144 (0x14b7d9a)
        ConvertToAssignments.func2: field.Set(stmt.Context, stmt.ReflectValue, value)
/Users/sam/go/pkg/mod/gorm.io/gorm@v1.23.5/callbacks/update.go:275 (0x14b62fa)
        ConvertToAssignments: assignValue(field, value)
/Users/sam/go/pkg/mod/gorm.io/gorm@v1.23.5/callbacks/update.go:73 (0x14b4fe4)
        Update.func1: if set := ConvertToAssignments(db.Statement); len(set) != 0 {
/Users/sam/go/pkg/mod/gorm.io/gorm@v1.23.5/callbacks.go:130 (0x146d632)
        (*processor).Execute: f(db)
/Users/sam/go/pkg/mod/gorm.io/gorm@v1.23.5/finisher_api.go:372 (0x1476811)
        (*DB).Updates: return tx.callbacks.Update().Execute(tx)
/Volumes/Data/Develop/Go/go-blog/controllers/blog.go:65 (0x1693364)
        UpdateBlog: models.DB.Model(&blog).Updates(input)
/Users/sam/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/context.go:168 (0x168a121)
        (*Context).Next: c.handlers[c.index](c)
/Users/sam/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/recovery.go:99 (0x168a10c)
        CustomRecoveryWithWriter.func1: c.Next()
/Users/sam/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/context.go:168 (0x1689246)
        (*Context).Next: c.handlers[c.index](c)
/Users/sam/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/logger.go:241 (0x1689229)
        LoggerWithConfig.func1: c.Next()
/Users/sam/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/context.go:168 (0x1688310)
        (*Context).Next: c.handlers[c.index](c)
/Users/sam/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/gin.go:555 (0x1687f78)
        (*Engine).handleHTTPRequest: c.Next()
/Users/sam/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/gin.go:511 (0x1687ab1)
        (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/usr/local/go/src/net/http/server.go:2916 (0x129bf5a)
        serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/go/src/net/http/server.go:1966 (0x1296f56)
        (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/local/go/src/runtime/asm_amd64.s:1571 (0x10648a0)
        goexit: BYTE    $0x90   // NOP

然而,当我按照教程进行操作时,一切都正常。以下是我的代码:

package controllers

import (
	"net/http"
	"samzhangjy/go-blog/models"

	"github.com/gin-gonic/gin"
)

type CreateBlogInput struct {
	Title   string `json:"title" binding:"required"`
	Content string `json:"content" binding:"required"`
}

func CreateBlog(c *gin.Context) {
	var input CreateBlogInput
	if err := c.ShouldBindJSON(&input); err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	blog := models.Blog{Title: input.Title, Content: input.Content}
	models.DB.Create(&blog)

	c.JSON(http.StatusOK, gin.H{"data": blog})
}

func FindBlogs(c *gin.Context) {
	var blogs []models.Blog
	models.DB.Find(&blogs)

	c.JSON(http.StatusOK, gin.H{"data": blogs})
}

func FindBlog(c *gin.Context) {
	var blog models.Blog

	if err := models.DB.First(&blog, "id = ?", c.Param("id")).Error; err != nil {
		c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"data": blog})
}

type UpdateBlogInput struct {
	Title   string `json:"title"`
	Content string `json:"content"`
}

func UpdateBlog(c *gin.Context) {
	var blog models.Blog
	if err := models.DB.Where("id = ?", c.Param("id")).First(&blog).Error; err != nil {
		c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": "record not found"})
		return
	}

	var input UpdateBlogInput

	if err := c.ShouldBindJSON(&input); err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	models.DB.Model(&blog).Updates(input)
	c.JSON(http.StatusOK, gin.H{"data": blog})
}

我已经阅读了这个Stackoverflow问题,但答案并不是很有帮助。当我将空数据传递给控制器时,一切都正常。但是,如果我在请求体中写入要更新的内容,例如:

{ "title": "lorem ipsum" }

它会崩溃并抛出上面提到的异常。

提前感谢!

更新

我的模型如下:

package models

import "time"

type Blog struct {
	ID        uint      `json:"id" gorm:"primary_key"`
	Title     string    `json:"title"`
	Content   string    `json:"content"`
	CreatedAt time.Time `json:"created_at"`
}
英文:

I'm trying to build a simple CRUD blog with Golang, Gin and GORM. However, when I wanted to update the blog content, the following error was triggered:

reflect: call of reflect.Value.SetString on uint Value
/usr/local/go/src/reflect/value.go:223 (0x10bfb25)
flag.mustBe: panic(&ValueError{methodName(), f.kind()})
/usr/local/go/src/reflect/value.go:2292 (0x10bfaa3)
Value.SetString: v.mustBe(String)
/Users/sam/go/pkg/mod/gorm.io/gorm@v1.23.5/schema/field.go:771 (0x144fcfc)
(*Field).setupValuerAndSetter.func11: field.ReflectValueOf(ctx, value).SetString(data)
/Users/sam/go/pkg/mod/gorm.io/gorm@v1.23.5/callbacks/update.go:144 (0x14b7d9a)
ConvertToAssignments.func2: field.Set(stmt.Context, stmt.ReflectValue, value)
/Users/sam/go/pkg/mod/gorm.io/gorm@v1.23.5/callbacks/update.go:275 (0x14b62fa)
ConvertToAssignments: assignValue(field, value)
/Users/sam/go/pkg/mod/gorm.io/gorm@v1.23.5/callbacks/update.go:73 (0x14b4fe4)
Update.func1: if set := ConvertToAssignments(db.Statement); len(set) != 0 {
/Users/sam/go/pkg/mod/gorm.io/gorm@v1.23.5/callbacks.go:130 (0x146d632)
(*processor).Execute: f(db)
/Users/sam/go/pkg/mod/gorm.io/gorm@v1.23.5/finisher_api.go:372 (0x1476811)
(*DB).Updates: return tx.callbacks.Update().Execute(tx)
/Volumes/Data/Develop/Go/go-blog/controllers/blog.go:65 (0x1693364)
UpdateBlog: models.DB.Model(&blog).Updates(input)
/Users/sam/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/context.go:168 (0x168a121)
(*Context).Next: c.handlers[c.index](c)
/Users/sam/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/recovery.go:99 (0x168a10c)
CustomRecoveryWithWriter.func1: c.Next()
/Users/sam/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/context.go:168 (0x1689246)
(*Context).Next: c.handlers[c.index](c)
/Users/sam/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/logger.go:241 (0x1689229)
LoggerWithConfig.func1: c.Next()
/Users/sam/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/context.go:168 (0x1688310)
(*Context).Next: c.handlers[c.index](c)
/Users/sam/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/gin.go:555 (0x1687f78)
(*Engine).handleHTTPRequest: c.Next()
/Users/sam/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/gin.go:511 (0x1687ab1)
(*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/usr/local/go/src/net/http/server.go:2916 (0x129bf5a)
serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/go/src/net/http/server.go:1966 (0x1296f56)
(*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/local/go/src/runtime/asm_amd64.s:1571 (0x10648a0)
goexit: BYTE    $0x90   // NOP

However, when I am following the tutorial, everything was all right. Here's my code:

package controllers

import (
	"net/http"
	"samzhangjy/go-blog/models"

	"github.com/gin-gonic/gin"
)

type CreateBlogInput struct {
	Title   string `json:"title" binding:"required"`
	Content string `json:"content" binding:"required"`
}

func CreateBlog(c *gin.Context) {
	var input CreateBlogInput
	if err := c.ShouldBindJSON(&input); err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	blog := models.Blog{Title: input.Title, Content: input.Content}
	models.DB.Create(&blog)

	c.JSON(http.StatusOK, gin.H{"data": blog})
}

func FindBlogs(c *gin.Context) {
	var blogs []models.Blog
	models.DB.Find(&blogs)

	c.JSON(http.StatusOK, gin.H{"data": blogs})
}

func FindBlog(c *gin.Context) {
	var blog models.Blog

	if err := models.DB.First(&blog, "id = ?", c.Param("id")).Error; err != nil {
		c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"data": blog})
}

type UpdateBlogInput struct {
	Title   string `json:"title"`
	Content string `json:"content"`
}

func UpdateBlog(c *gin.Context) {
	var blog models.Blog
	if err := models.DB.Where("id = ?", c.Param("id")).First(&blog).Error; err != nil {
		c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": "record not found"})
		return
	}

	var input UpdateBlogInput

	if err := c.ShouldBindJSON(&input); err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	models.DB.Model(&blog).Updates(input)
	c.JSON(http.StatusOK, gin.H{"data": blog})
}

I have read this Stackoverflow question but the answer was not that helpful. When I passed empty data to the controller, everything was doing fine. But if I write something to update in the request body, e.g.:

{ "title": "lorem ipsum" }

It will crash and throw the exception mentioned above.

Thanks in advance!

UPDATE:

My models below:

package models

import "time"

type Blog struct {
	ID        uint      `json:"id" gorm:"primary_key"`
	Title     string    `json:"title"`
	Content   string    `json:"content"`
	CreatedAt time.Time `json:"created_at"`
}

答案1

得分: 4

可能是因为您在更新时使用的结构与models.Blog不同。您可以尝试以下代码:

func UpdateBlog(c *gin.Context) {
    var blog models.Blog
    if err := models.DB.Where("id = ?", c.Param("id")).First(&blog).Error; err != nil {
        c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": "记录未找到"})
        return
    }

    var input UpdateBlogInput

    if err := c.ShouldBindJSON(&input); err != nil {
        c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    updateBlog := models.Blog{Title: input.Title, Content: input.Content}

    models.DB.Model(&blog).Updates(&updateBlog)
    c.JSON(http.StatusOK, gin.H{"data": updateBlog})
}

请注意,这只是一个翻译,我无法判断代码是否正确或完整。

英文:

It might be because you are using a different struct than models.Blog to update. Could you try the following:

func UpdateBlog(c *gin.Context) {
    var blog models.Blog
    if err := models.DB.Where("id = ?", c.Param("id")).First(&blog).Error; err != nil {
        c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": "record not found"})
        return
    }

    var input UpdateBlogInput

    if err := c.ShouldBindJSON(&input); err != nil {
        c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    updateBlog := models.Blog{Title: input.Title, Content: input.Content}

    models.DB.Model(&blog).Updates(&updateBlog)
    c.JSON(http.StatusOK, gin.H{"data": updateBlog})
}

huangapple
  • 本文由 发表于 2022年6月2日 15:40:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/72472405.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定