仅在更新时 Gorm 和 Gin 错误 500
Gorm and Gin error 500 only when Updating
我有一个非常简单的任务列表 CRUD,到目前为止我能够创建、列出所有、按 ID 列出和删除记录,但是当我尝试更新时,它给我以下错误:
go-proj | reflect: call of reflect.Value.Field on string Value
go-proj | /usr/local/go/src/reflect/value.go:850 (0x4a2464)
go-proj | Value.Field: panic(&ValueError{"reflect.Value.Field", v.kind()})
go-proj | /go/pkg/mod/gorm.io/gorm@v1.20.7/schema/field.go:393 (0x996e50)
go-proj | (*Field).setupValuerAndSetter.func2: fieldValue := reflect.Indirect(value).Field(field.StructField.Index[0]).Field(field.StructField.Index[1])
go-proj | /go/pkg/mod/gorm.io/gorm@v1.20.7/callbacks/update.go:230 (0xb3e3f0)
go-proj | ConvertToAssignments: value, isZero := field.ValueOf(updatingValue)
go-proj | /go/pkg/mod/gorm.io/gorm@v1.20.7/callbacks/update.go:64 (0xb3bfd9)
go-proj | Update: if set := ConvertToAssignments(db.Statement); len(set) != 0 {
go-proj | /go/pkg/mod/gorm.io/gorm@v1.20.7/callbacks.go:105 (0x9a5b7c)
go-proj | (*processor).Execute: f(db)
go-proj | /go/pkg/mod/gorm.io/gorm@v1.20.7/finisher_api.go:303 (0x9ad886)
go-proj | (*DB).Updates: tx.callbacks.Update().Execute(tx)
go-proj | /app/app/controllers/listController.go:70 (0xb49c7b)
go-proj | Update: if err := models.DB.Model(&list).Updates(input).Error; err != nil {
go-proj | /go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/context.go:161 (0x93d01a)
go-proj | (*Context).Next: c.handlers[c.index](c)
go-proj | /go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/recovery.go:83 (0x951004)
go-proj | RecoveryWithWriter.func1: c.Next()
go-proj | /go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/context.go:161 (0x93d01a)
go-proj | (*Context).Next: c.handlers[c.index](c)
go-proj | /go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/logger.go:241 (0x950104)
go-proj | LoggerWithConfig.func1: c.Next()
go-proj | /go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/context.go:161 (0x93d01a)
go-proj | (*Context).Next: c.handlers[c.index](c)
go-proj | /go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/gin.go:409 (0x947359)
go-proj | (*Engine).handleHTTPRequest: c.Next()
go-proj | /go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/gin.go:367 (0x946a4c)
go-proj | (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
go-proj | /usr/local/go/src/net/http/server.go:2843 (0x6cd7c2)
go-proj | serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
go-proj | /usr/local/go/src/net/http/server.go:1925 (0x6c8ecc)
go-proj | (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
go-proj | /usr/local/go/src/runtime/asm_amd64.s:1374 (0x46cba0)
go-proj | goexit: BYTE [=10=]x90 // NOP
go-proj |
go-proj-nginx | 172.27.0.1 - - [20/Nov/2020:17:32:56 +0000] "PUT /list/3 HTTP/1.1" 500 0 "-" "PostmanRuntime/7.6.0"
我将提取代码中唯一重要的部分:
路由器:
r := gin.Default()
r.PUT("/list/:id", controllers.Update)
型号:
type List struct {
gorm.Model
UserId uint
Title string
Status uint
}
控制器:
type UpdateListInput struct {
Title string `json:"title"`
Status uint `json:"status"`
}
func Update(c *gin.Context) {
var list models.List
if err := models.DB.Where("id = ?", c.Param("id")).First(&list).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Record not found"})
return
}
var input UpdateListInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := models.DB.Model(&list).Updates(input).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
c.JSON(http.StatusOK, gin.H{"data": list})
}
我将以下 JSON 发送给 /list/:id
:
{
"title": "Shopping List 2",
"status": 2
}
有关更多信息,您可以在 GitHub 上查看我的存储库文件夹 .docker/
,也许我在 Nginx、Postgres 甚至 Golang 配置上搞砸了一些东西,因为我是 运行我在容器上的应用程序。
编辑1:
我通过硬编码要在我的控制器中更新的数据来使其工作:
func Update(c *gin.Context) {
var list models.List
if err := models.DB.Where("id = ?", c.Param("id")).First(&list).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Record not found"})
return
}
input := map[string]interface{}{
"title": "AAAAAAAAAa",
"status": 3,
}
if err := models.DB.Model(&list).Updates(input).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"data": list})
}
好吧,这是一个解决方法,我可能会在 Gorm's Github because I don't think that this is the right way of doing it, the only thing that I'd to do is convert from UpdateListInput struct
to a variable of map[string]interface{}
using reflect 包
上打开一个问题
这是我的控制器:
func Update(c *gin.Context) {
var list models.List
if err := models.DB.Where("id = ?", c.Param("id")).First(&list).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Record not found"})
return
}
var input UpdateListInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
v := reflect.ValueOf(input)
typeOfV := v.Type()
inputData := map[string]interface{}{}
for i := 0; i < v.NumField(); i++ {
inputData[typeOfV.Field(i).Name] = v.Field(i).Interface()
}
if err := models.DB.Model(&list).Updates(inputData).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"data": list})
}
在控制器中试试这个:
data := models.List{Title: input.Title,Status: input.Status}
if err := models.DB.Model(&list).Updates(&data).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
c.JSON(http.StatusOK, gin.H{"data": data})
我有一个非常简单的任务列表 CRUD,到目前为止我能够创建、列出所有、按 ID 列出和删除记录,但是当我尝试更新时,它给我以下错误:
go-proj | reflect: call of reflect.Value.Field on string Value
go-proj | /usr/local/go/src/reflect/value.go:850 (0x4a2464)
go-proj | Value.Field: panic(&ValueError{"reflect.Value.Field", v.kind()})
go-proj | /go/pkg/mod/gorm.io/gorm@v1.20.7/schema/field.go:393 (0x996e50)
go-proj | (*Field).setupValuerAndSetter.func2: fieldValue := reflect.Indirect(value).Field(field.StructField.Index[0]).Field(field.StructField.Index[1])
go-proj | /go/pkg/mod/gorm.io/gorm@v1.20.7/callbacks/update.go:230 (0xb3e3f0)
go-proj | ConvertToAssignments: value, isZero := field.ValueOf(updatingValue)
go-proj | /go/pkg/mod/gorm.io/gorm@v1.20.7/callbacks/update.go:64 (0xb3bfd9)
go-proj | Update: if set := ConvertToAssignments(db.Statement); len(set) != 0 {
go-proj | /go/pkg/mod/gorm.io/gorm@v1.20.7/callbacks.go:105 (0x9a5b7c)
go-proj | (*processor).Execute: f(db)
go-proj | /go/pkg/mod/gorm.io/gorm@v1.20.7/finisher_api.go:303 (0x9ad886)
go-proj | (*DB).Updates: tx.callbacks.Update().Execute(tx)
go-proj | /app/app/controllers/listController.go:70 (0xb49c7b)
go-proj | Update: if err := models.DB.Model(&list).Updates(input).Error; err != nil {
go-proj | /go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/context.go:161 (0x93d01a)
go-proj | (*Context).Next: c.handlers[c.index](c)
go-proj | /go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/recovery.go:83 (0x951004)
go-proj | RecoveryWithWriter.func1: c.Next()
go-proj | /go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/context.go:161 (0x93d01a)
go-proj | (*Context).Next: c.handlers[c.index](c)
go-proj | /go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/logger.go:241 (0x950104)
go-proj | LoggerWithConfig.func1: c.Next()
go-proj | /go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/context.go:161 (0x93d01a)
go-proj | (*Context).Next: c.handlers[c.index](c)
go-proj | /go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/gin.go:409 (0x947359)
go-proj | (*Engine).handleHTTPRequest: c.Next()
go-proj | /go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/gin.go:367 (0x946a4c)
go-proj | (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
go-proj | /usr/local/go/src/net/http/server.go:2843 (0x6cd7c2)
go-proj | serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
go-proj | /usr/local/go/src/net/http/server.go:1925 (0x6c8ecc)
go-proj | (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
go-proj | /usr/local/go/src/runtime/asm_amd64.s:1374 (0x46cba0)
go-proj | goexit: BYTE [=10=]x90 // NOP
go-proj |
go-proj-nginx | 172.27.0.1 - - [20/Nov/2020:17:32:56 +0000] "PUT /list/3 HTTP/1.1" 500 0 "-" "PostmanRuntime/7.6.0"
我将提取代码中唯一重要的部分:
路由器:
r := gin.Default()
r.PUT("/list/:id", controllers.Update)
型号:
type List struct {
gorm.Model
UserId uint
Title string
Status uint
}
控制器:
type UpdateListInput struct {
Title string `json:"title"`
Status uint `json:"status"`
}
func Update(c *gin.Context) {
var list models.List
if err := models.DB.Where("id = ?", c.Param("id")).First(&list).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Record not found"})
return
}
var input UpdateListInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := models.DB.Model(&list).Updates(input).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
c.JSON(http.StatusOK, gin.H{"data": list})
}
我将以下 JSON 发送给 /list/:id
:
{
"title": "Shopping List 2",
"status": 2
}
有关更多信息,您可以在 GitHub 上查看我的存储库文件夹 .docker/
,也许我在 Nginx、Postgres 甚至 Golang 配置上搞砸了一些东西,因为我是 运行我在容器上的应用程序。
编辑1: 我通过硬编码要在我的控制器中更新的数据来使其工作:
func Update(c *gin.Context) {
var list models.List
if err := models.DB.Where("id = ?", c.Param("id")).First(&list).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Record not found"})
return
}
input := map[string]interface{}{
"title": "AAAAAAAAAa",
"status": 3,
}
if err := models.DB.Model(&list).Updates(input).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"data": list})
}
好吧,这是一个解决方法,我可能会在 Gorm's Github because I don't think that this is the right way of doing it, the only thing that I'd to do is convert from UpdateListInput struct
to a variable of map[string]interface{}
using reflect 包
这是我的控制器:
func Update(c *gin.Context) {
var list models.List
if err := models.DB.Where("id = ?", c.Param("id")).First(&list).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Record not found"})
return
}
var input UpdateListInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
v := reflect.ValueOf(input)
typeOfV := v.Type()
inputData := map[string]interface{}{}
for i := 0; i < v.NumField(); i++ {
inputData[typeOfV.Field(i).Name] = v.Field(i).Interface()
}
if err := models.DB.Model(&list).Updates(inputData).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"data": list})
}
在控制器中试试这个:
data := models.List{Title: input.Title,Status: input.Status}
if err := models.DB.Model(&list).Updates(&data).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
c.JSON(http.StatusOK, gin.H{"data": data})