Go GORM 有很多关系。如何将数据存储到MYSQL DB

     2023-03-29     100

关键词:

【中文标题】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

【讨论】:

如何使用 gorm 在 postgresQL 数据库中存储一个点

】如何使用gorm在postgresQL数据库中存储一个点【英文标题】:HowtostoreapointinpostgresSQLdatabaseusinggorm【发布时间】:2016-06-1720:15:25【问题描述】:我正在尝试在go服务器上使用GORM将Point变量存储在SQL数据库中,我尝试到处寻找,但我... 查看详情

go语言学习之旅--gorm(代码片段)

...删除一条记录根据主键删除批量删除gorm概述ORM简介对象关系映射(ObjectRelationalMapping,简称ORM)模式是一种为了解决面向对象与关系数据库(如mysql数据库)存在的互不匹配的现象的技术。简单的说,ORM是... 查看详情

go语言学习之旅--gorm(代码片段)

...删除一条记录根据主键删除批量删除gorm概述ORM简介对象关系映射(ObjectRelationalMapping,简称ORM)模式是一种为了解决面向对象与关系数据库(如mysql数据库)存在的互不匹配的现象的技术。简单的说,ORM是... 查看详情

从java到go搭建go的orm框架gorm(代码片段)

【提问】如何使用Goland软件,搭建一个ORM框架GORM?【解答】具体步骤如下:1、检查Go的安装在任意目录执行如下命令:goversion若有如下返回,则安装成功;如果报异常,则重新安装golanggoversiongo1.19.1darw... 查看详情

从java到go搭建go的orm框架gorm(代码片段)

【提问】如何使用Goland软件,搭建一个ORM框架GORM?【解答】具体步骤如下:1、检查Go的安装在任意目录执行如下命令:goversion若有如下返回,则安装成功;如果报异常,则重新安装golanggoversiongo1.19.1darw... 查看详情

从java到go搭建go的orm框架gorm(代码片段)

【提问】如何使用Goland软件,搭建一个ORM框架GORM?【解答】具体步骤如下:1、检查Go的安装在任意目录执行如下命令:goversion若有如下返回,则安装成功;如果报异常,则重新安装golanggoversiongo1.19.1darw... 查看详情

如何将事物组合映射到关系数据库?

】如何将事物组合映射到关系数据库?【英文标题】:Howtomapcombinationsofthingstoarelationaldatabase?【发布时间】:2011-02-2108:02:27【问题描述】:我有一个表,它的记录代表某些对象。为简单起见,我将假设该表只有一列,即唯一的Obje... 查看详情

如何通过单个语句将嵌套关系提取到数组中

...607:27:32【问题描述】:我有四个模型,每个模型之间都有很多关系。A有很多BB有很多CC有很多D我的主要模型是A,我想通过A获取D。我正在这样查询以获取D。A::with(\'B.C.D\')->get();我正在这 查看详情

如何在 Go-Gorm 中禁用默认错误记录器

】如何在Go-Gorm中禁用默认错误记录器【英文标题】:HowtodisabledefaulterrorloggerinGo-Gorm【发布时间】:2019-09-1709:49:46【问题描述】:我在MySQL中使用GORM,我遇到并处理了错误Error1062:Duplicateentry。问题是它仍然打印到控制台。gym/models/... 查看详情

go语言学习之旅--gorm(代码片段)

...删除一条记录根据主键删除批量删除gorm概述ORM简介对象关系映射࿰ 查看详情

go-zero我是如何把gorm整合进go-zero的?(代码片段)

原创不易,未经允许,请勿转载。go-zero提供的代码生成器里面,没有提供orm框架操作,但是提供了遍历的缓存操作。但是gorm框架的话,没有比较好的缓存插件,虽然有一个gcache,但不支持gorm2.0版本。所以... 查看详情

gorm / go 如何正确连接两个表?

】gorm/go如何正确连接两个表?【英文标题】:gorm/gohowtojointwotablesproperly?【发布时间】:2022-01-1217:54:54【问题描述】:我的消息结构;typeMessagestructIdint`json:"id"gorm:"primaryKey;AUTO_INCREMENT"`Messagestring`json:"message"`Senderint`json:"sender"gorm: 查看详情

go-zero我是如何把gorm整合进go-zero的?(代码片段)

原创不易,未经允许,请勿转载。go-zero提供的代码生成器里面,没有提供orm框架操作,但是提供了遍历的缓存操作。但是gorm框架的话,没有比较好的缓存插件,虽然有一个gcache,但不支持gorm2.0版本。所以... 查看详情

gorm高级查询

...级,越复杂的查询,也同时意味着高耗,但是平时有一些数据少,但是业务复杂的场景,可以使用下。这里主要说明的是go中使用gorm进务查询。有时候代码是可需要映射到一个map结构,不需要映射到一个结构体中,可以写成如下... 查看详情

核心数据,关系 - 将多个选定的行存储到实体

】核心数据,关系-将多个选定的行存储到实体【英文标题】:CoreData,Relationship-storemultipleselectedrowstoentity【发布时间】:2018-07-0910:48:16【问题描述】:我需要帮助-我想通过关系将tableView中的多个选定行存储到一个实体中)假设我... 查看详情

如何将数据从 MATLAB 存储到 Access DB?

...库中的视频......你能帮帮我吗?【问题讨论】:问题中有很多错误。我试图编 查看详情

如何使用 GORM 测试实例是不是持久化到数据库中?

】如何使用GORM测试实例是不是持久化到数据库中?【英文标题】:HowdoItestifanInstanceispersistedintheDatabasewithGORM?如何使用GORM测试实例是否持久化到数据库中?【发布时间】:2014-09-1916:48:03【问题描述】:当我将实例另存为:test.save... 查看详情

如何在 MySQL 数据库中存储一对多关系?

...题讨论】:这只是一对多的关系。例如,一个用户可以有很多电话号码。这将在 查看详情