【问题标题】:Go GORM has many relationship. How to store the data to MYSQL DBGo GORM 有很多关系。如何将数据存储到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 框架。

【问题讨论】:

    标签: mysql go go-gorm


    【解决方案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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-27
      • 2021-10-27
      • 1970-01-01
      • 1970-01-01
      • 2021-12-26
      • 1970-01-01
      • 2012-09-06
      • 1970-01-01
      相关资源
      最近更新 更多