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

Time:06-03

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/[email protected]/schema/field.go:771 (0x144fcfc)
        (*Field).setupValuerAndSetter.func11: field.ReflectValueOf(ctx, value).SetString(data)
/Users/sam/go/pkg/mod/gorm.io/[email protected]/callbacks/update.go:144 (0x14b7d9a)
        ConvertToAssignments.func2: field.Set(stmt.Context, stmt.ReflectValue, value)
/Users/sam/go/pkg/mod/gorm.io/[email protected]/callbacks/update.go:275 (0x14b62fa)
        ConvertToAssignments: assignValue(field, value)
/Users/sam/go/pkg/mod/gorm.io/[email protected]/callbacks/update.go:73 (0x14b4fe4)
        Update.func1: if set := ConvertToAssignments(db.Statement); len(set) != 0 {
/Users/sam/go/pkg/mod/gorm.io/[email protected]/callbacks.go:130 (0x146d632)
        (*processor).Execute: f(db)
/Users/sam/go/pkg/mod/gorm.io/[email protected]/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/[email protected]/context.go:168 (0x168a121)
        (*Context).Next: c.handlers[c.index](c)
/Users/sam/go/pkg/mod/github.com/gin-gonic/[email protected]/recovery.go:99 (0x168a10c)
        CustomRecoveryWithWriter.func1: c.Next()
/Users/sam/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:168 (0x1689246)
        (*Context).Next: c.handlers[c.index](c)
/Users/sam/go/pkg/mod/github.com/gin-gonic/[email protected]/logger.go:241 (0x1689229)
        LoggerWithConfig.func1: c.Next()
/Users/sam/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:168 (0x1688310)
        (*Context).Next: c.handlers[c.index](c)
/Users/sam/go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:555 (0x1687f78)
        (*Engine).handleHTTPRequest: c.Next()
/Users/sam/go/pkg/mod/github.com/gin-gonic/[email protected]/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"`
}

CodePudding user response:

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})
}
  • Related