Go GORM 有很多关系。如何将数据存储到MYSQL DB
Posted
技术标签:
【中文标题】Go GORM 有很多关系。如何将数据存储到MYSQL DB【英文标题】:Go GORM has many relationship. How to store the data to MYSQL DB 【发布时间】:2021-12-28 18:41:06 【问题描述】:我是后端新手,也是 golang 和 gorm 的新手。
我通过在 go 和 gorm 中使用 has-many 构建简单的 api 来学习后端。
我正在尝试使用“TripId”的外键创建“Trip”表和“SingleTrip”表
基本上,一次旅行有一段singleTrip
这里是代码, 我有两个模型是
type Base struct
gorm.Model
ID string `gorm:"primary_key;not_null" json:"id"`
type Trip struct
Base
UserId string `gorm:"not_null" json:"user_id"`
TripDetail []SingleTrip `gorm:"foreignKey:Id;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" json:"trip_detail"`
type SingleTrip struct
gorm.Model
Id string `gorm:"primary_id" json:"id"`
TripId string `gorm:"primary_key;not_null" json:"trip_id"`
TripDate string `gorm:"size:255;not_null;" json:"trip_date"`
FromAddress string `gorm:"size:255;not_null;" json:"from_address"`
ToAddress string `gorm:"size:255;not_null;" json:"to_address"`
Distance float64 `gorm:"not_null;" json:"distance"`
Reason string `gorm:"size:255;not_null;" json:"reason"`
Comments string `gorm:"size:255;not_null;" json:"comments"`
Receipts string `gorm:"size:255;not_null;" json:"receipt"`
Amount float64 `gorm:"not_null;" json:"amount"`
RoundTrip string `gorm:"size:255;not_null;" json:"round_trip"`
func (trip *Trip) BeforeCreate(gorm *gorm.DB) error
tripId := uuid.New()
trip.ID = tripId.String()
return nil
func (singleTrip *SingleTrip) BeforeCreate(gorm *gorm.DB) error
id := uuid.New()
singleTrip.Id = id.String()
return nil
这是我尝试保存在 mysql db 中的请求正文
"user_id": "d4be5cbc-4377-11ec-a108-2e7a8ebc414a",
"trip_detail": [
"trip_date": "05/29/2021",
"from_address":"from address field",
"to_address": "to address field",
"distance": 50.2,
"reason": "dinner",
"comments": "this is comments field",
"receipt": "for lunch",
"amount": 50.0,
"round_trip": "round field"
,
"trip_date": "07/29/2021",
"from_address": "some address",
"to_address": "Some to address",
"distance": 50.2,
"reason": "dinner",
"comments": "this is comment field",
"receipt": "for meeting",
"amount": 50.0,
"round_trip": "round field"
]
这是 SaveTrip 方法
func (trip *Trip) SaveTrip(db *gorm.DB) (*Trip, error)
err := db.Debug().Create(&trip).Error
if err != nil
return &Trip, err
return trip, nil
控制器 trip_controller.go
func (server *Server) CreateTrip(context *gin.Context)
errMessage := map[string]string
body, err := ioutil.ReadAll(context.Request.Body)
trip := models.Trip
if err != nil
errMessage["Invalid Request"] = "Invalid Request"
context.JSON(http.StatusUnprocessableEntity, gin.H
"status": http.StatusUnprocessableEntity,
"error": errMessage,
)
return
err = json.Unmarshal([]byte(body), &trip)
if err != nil
errMessage["Unable to Unmarshall"] = "Unable to unmarshal"
context.JSON(http.StatusUnprocessableEntity, gin.H
"status": http.StatusUnprocessableEntity,
"error": errMessage,
)
return
trip.Prepare()
validatingErrMessage := map[string]string
validatingErrMessage = trip.ValidatingTripData("create")
if len(validatingErrMessage) > 0
errMessage = validatingErrMessage
context.JSON(http.StatusUnprocessableEntity, gin.H
"status": http.StatusUnprocessableEntity,
"error": errMessage,
)
return
createdTrip, err := trip.SaveTrip(server.DB)
if err != nil
formattedError := utils.FormatError(err.Error())
context.JSON(http.StatusInternalServerError, gin.H
"status": http.StatusInternalServerError,
"error": err.Error(),
)
return
context.JSON(http.StatusOK, gin.H
"status": http.StatusOK,
"response": createdTrip,
)
这是我从邮递员那里得到的回复
"response":
"ID": 0,
"CreatedAt": "2021-11-18T00:08:55.357+05:30",
"UpdatedAt": "2021-11-18T00:08:55.357+05:30",
"DeletedAt": null,
"id": "52a44faa-437a-4695-82c7-b45cdab9e6d1",
"user_id": "d4be5cbc-4377-11ec-a108-2e7a8ebc414a",
"trip_detail": [
"ID": 0,
"CreatedAt": "2021-11-18T00:08:55.362+05:30",
"UpdatedAt": "2021-11-18T00:08:55.362+05:30",
"DeletedAt": null,
"Id": "52a44faa-437a-4695-82c7-b45cdab9e6d1",
"trip_date": "05/29/2021",
"from_address": "some address",
"to_address": "some - to address",
"distance": 50.2,
"reason": "dinner",
"comments": "this is comments field",
"receipt": "for lunch",
"amount": 50,
"round_trip": "round field"
,
"ID": 0,
"CreatedAt": "2021-11-18T00:08:55.362+05:30",
"UpdatedAt": "2021-11-18T00:08:55.362+05:30",
"DeletedAt": null,
"Id": "52a44faa-437a-4695-82c7-b45cdab9e6d1",
"trip_date": "07/29/2021",
"from_address": "some address",
"to_address": "Some to address",
"distance": 50.2,
"reason": "dinner",
"comments": "this is comment field",
"receipt": "for meeting",
"amount": 50,
"round_trip": "round field"
]
,
"status": 200
但数据没有存储在数据库中
当尝试将数据存储到数据库时,我遇到了错误
如何将数据存储在Db中,或者有没有其他方法可以存储值?
我正在使用 golang、gorm、gin 框架。
【问题讨论】:
【参考方案1】:对不起,如果我语法不好。
更改这行代码
func (singleTrip *SingleTrip) BeforeCreate(gorm *gorm.DB) error
/*
fmt.Println(singleTrip.Id) // this value will be Trip (parent) ID
*/
id := uuid.New()
// WRONG
// singleTrip.Id = id.String()
/*
Maybe This is what you want
TripId is the primary Key
not Id (from how you define the model tag)
*/
singleTrip.TripId = id.String()
return nil
SingleTrip
中的Id
(在这种情况下,是外键,而不是主键)不能被BeforeCreate
覆盖,因为gorm 关系已经处理了来自Trip
的Id 值为ID
(父母)。如果需要,您可以尝试记录该值。
这将导致 MySQL 本身出错,因为在事务中新的 id 没有记录在父 (Trip
) 主键中。
还有一点建议,明智地选择外键名称,例如 trip_id
适合 Trip
x SingleTrip
外键而不是 Id
。刚开始理解模型很混乱。
完整代码:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
var DB *gorm.DB
func main()
databaseConfig := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?multiStatements=true&parseTime=true", "root", "", "127.0.0.1", "3306", "tester")
DB, _ = gorm.Open(mysql.Open(databaseConfig), &gorm.Config
Logger: logger.Default.LogMode(logger.Info),
)
sqlDB, _ := DB.DB()
defer sqlDB.Close()
DB.AutoMigrate(&Trip, &SingleTrip)
router := gin.Default()
router.POST("/", CreateTrip)
router.Run(":8080")
type Base struct
gorm.Model
ID string `gorm:"primary_key;not_null" json:"id"`
type Trip struct
// Base
gorm.Model
ID string `gorm:"size:255;primary_key;not_null" json:"id"`
UserId string `gorm:"not_null" json:"user_id"`
TripDetail []SingleTrip `gorm:"foreignKey:Id;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" json:"trip_detail"`
type SingleTrip struct
gorm.Model
Id string `gorm:"size:255;primary_id" json:"id"`
TripId string `gorm:"primary_key;not_null" json:"trip_id"`
TripDate string `gorm:"size:255;not_null;" json:"trip_date"`
FromAddress string `gorm:"size:255;not_null;" json:"from_address"`
ToAddress string `gorm:"size:255;not_null;" json:"to_address"`
Distance float64 `gorm:"not_null;" json:"distance"`
Reason string `gorm:"size:255;not_null;" json:"reason"`
Comments string `gorm:"size:255;not_null;" json:"comments"`
Receipts string `gorm:"size:255;not_null;" json:"receipt"`
Amount float64 `gorm:"not_null;" json:"amount"`
RoundTrip string `gorm:"size:255;not_null;" json:"round_trip"`
func (trip *Trip) BeforeCreate(gorm *gorm.DB) error
tripId := uuid.New()
trip.ID = tripId.String()
return nil
func (singleTrip *SingleTrip) BeforeCreate(gorm *gorm.DB) error
/*
fmt.Println(singleTrip.Id) // this value will be Trip (parent) ID
*/
id := uuid.New()
// WRONG
// singleTrip.Id = id.String()
/*
Maybe This is what you want
TripId is the primary Key
not Id (from how you define the model tag)
*/
singleTrip.TripId = id.String()
return nil
func (trip *Trip) SaveTrip(db *gorm.DB) (*Trip, error)
err := db.Debug().Create(&trip).Error
if err != nil
return &Trip, err
return trip, nil
// =======================================================
func CreateTrip(context *gin.Context)
errMessage := map[string]string
body, err := ioutil.ReadAll(context.Request.Body)
trip := Trip
if err != nil
errMessage["Invalid Request"] = "Invalid Request"
context.JSON(http.StatusUnprocessableEntity, gin.H
"status": http.StatusUnprocessableEntity,
"error": errMessage,
)
return
err = json.Unmarshal([]byte(body), &trip)
if err != nil
errMessage["Unable to Unmarshall"] = "Unable to unmarshal"
context.JSON(http.StatusUnprocessableEntity, gin.H
"status": http.StatusUnprocessableEntity,
"error": errMessage,
)
return
fmt.Printf("Trip: %+v", trip)
// fmt.Printf("Trip: %+v", trip.TripDetail[0].ID)
// fmt.Printf("Trip: %+v", trip.TripDetail[0].Id)
// trip.Prepare()
// validatingErrMessage := map[string]string
// validatingErrMessage = trip.ValidatingTripData("create")
// if len(validatingErrMessage) > 0
// errMessage = validatingErrMessage
// context.JSON(http.StatusUnprocessableEntity, gin.H
// "status": http.StatusUnprocessableEntity,
// "error": errMessage,
// )
// return
//
createdTrip, err := trip.SaveTrip(DB)
if err != nil
// formattedError := utils.FormatError(err.Error())
context.JSON(http.StatusInternalServerError, gin.H
"status": http.StatusInternalServerError,
"error": err.Error(),
)
return
context.JSON(http.StatusOK, gin.H
"status": http.StatusOK,
"response": createdTrip,
)
Output
【讨论】:
以上是关于Go GORM 有很多关系。如何将数据存储到MYSQL DB的主要内容,如果未能解决你的问题,请参考以下文章