GORM 一对一映射问题

GORM One-to One mapping issue

我对 GORM 映射有一个奇怪的问题,我有两个如下所示的结构。

type ParcelOrder struct {
    gorm.Model
    ID                 int                `json:"id"`
    SenderId           uint               `json:"sender_id"`
    OrderID            string             `json:"order_id"`
    PickupAddress      string             `json:"pickup_address"`
    DeliveryAddress    string             `json:"delivery_address"`
    CreatedAt          time.Time          `json:"created_at"`
    UpdatedAt          time.Time          `json:"updated_at"`
    DeletedAt          sql.NullTime       `json:"deleted_at"`
    ParcelOrderDetails ParcelOrderDetails `gorm:"foreignKey:ParcelOrderID"`
}
type ParcelOrderDetails struct {
    gorm.Model
    ID            int           `json:"id"`
    BikerID       sql.NullInt32 `json:"biker_id"`
    ParcelOrderID int           `json:"parcel_order_id"`
    PickupTime    sql.NullTime  `json:"pickup_time"`
    DeliveryTime  sql.NullTime  `json:"delivery_time"`
    Status        int           `json:"status"`
    CreatedAt     time.Time     `json:"created_at"`
    UpdatedAt     time.Time     `json:"updated_at"`
    DeletedAt     sql.NullTime  `json:"deleted_at"`
}

我正在使用 Mysql 数据库,当我尝试创建订单时它没有在第二个 table 上创建条目。 为了创建,我使用以下代码

order := ParcelOrder{
        DeliveryAddress: pickupdata.DeliveryAddress,
        PickupAddress:   pickupdata.PickupAddress,
        OrderID:         GetUniqueID(),
        SenderId:        userId,
        ParcelOrderDetails: ParcelOrderDetails{
            Status: 0,
        },
    }
connection.Create(&order)

此外,当我尝试从 table 中获取数据时,我收到如下错误

SELECT `parcel_orders`.`id`,`parcel_orders`.`created_at`,`parcel_orders`.`updated_at`,`parcel_orders`.`deleted_at`,`parcel_orders`.`sender_id`,`parcel_orders`.`order_id`,`parcel_orders`.`pickup_address`,`parcel_orders`.`delivery_address`,`ParcelOrderDetails`.`id` AS `ParcelOrderDetails__id`,`ParcelOrderDetails`.`created_at` AS `ParcelOrderDetails__created_at`,`ParcelOrderDetails`.`updated_at` AS `ParcelOrderDetails__updated_at`,`ParcelOrderDetails`.`deleted_at` AS `ParcelOrderDetails__deleted_at`,`ParcelOrderDetails`.`biker_id` AS `ParcelOrderDetails__biker_id`,`ParcelOrderDetails`.`parcel_order_id` AS `ParcelOrderDetails__parcel_order_id`,`ParcelOrderDetails`.`pickup_time` AS `ParcelOrderDetails__pickup_time`,`ParcelOrderDetails`.`delivery_time` AS `ParcelOrderDetails__delivery_time`,`ParcelOrderDetails`.`status` AS `ParcelOrderDetails__status` FROM `parcel_orders` ParcelOrder LEFT JOIN `parcel_order_details` `ParcelOrderDetails` ON `parcel_orders`.`id` = `ParcelOrderDetails`.`parcel_order_id` WHERE ParcelOrder.sender_id = 2

我的获取代码如下。提取问题非常奇怪,因为别名被指定为 ParcelOrder,因此未使用该名称标识的字段仍然使用 parcel_orders 实际 table 名称

db.Joins("ParcelOrder").Joins("ParcelOrderDetails").Where("ParcelOrder.sender_id = ?", userId).Find(&order)

数据库不是使用 Go 应用程序创建的,而是使用 Laravel 应用程序创建的。我正在尝试 read/write 数据到该数据库。

有什么想法吗?

答案简单但难以理解。

您只需添加零钱:

ParcelOrderDetails ParcelOrderDetails `gorm:"foreignKey:ParcelOrderID"`

进入

ParcelOrderDetails *ParcelOrderDetails `gorm:"foreignKey:ParcelOrderID"`

原因是 ParcelOrderDetails 会在每次初始化 ParcelOrder 时创建一个空模型(非空),当然在某些情况下我们不打算意外创建 ParcelOrderOrderDetails 因为这是一个空模型,我认为 GORM 可以处理这种情况。

所以如果你把它变成*ParcelOrderOrderDetails,默认情况下它将是nil,这意味着GORM不会创建ParcelOrderOrderDetails,反之亦然。

这是我的完整代码

// 
package main

import (
    "database/sql"
    "fmt"
    "time"

    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "gorm.io/gorm/logger"
)

type ParcelOrder struct {
    gorm.Model
    ID                 int                `json:"id"`
    SenderId           uint               `json:"sender_id"`
    OrderID            string             `json:"order_id"`
    PickupAddress      string             `json:"pickup_address"`
    DeliveryAddress    string             `json:"delivery_address"`
    CreatedAt          time.Time          `json:"created_at"`
    UpdatedAt          time.Time          `json:"updated_at"`
    DeletedAt          sql.NullTime       `json:"deleted_at"`
    ParcelOrderDetails *ParcelOrderDetails `gorm:"foreignKey:ParcelOrderID"`
}

type ParcelOrderDetails struct {
    gorm.Model
    ID            int           `json:"id"`
    BikerID       sql.NullInt32 `json:"biker_id"`
    ParcelOrderID int           `json:"parcel_order_id"`
    PickupTime    sql.NullTime  `json:"pickup_time"`
    DeliveryTime  sql.NullTime  `json:"delivery_time"`
    Status        int           `json:"status"`
    CreatedAt     time.Time     `json:"created_at"`
    UpdatedAt     time.Time     `json:"updated_at"`
    DeletedAt     sql.NullTime  `json:"deleted_at"`
}

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(&ParcelOrder{}, &ParcelOrderDetails{})

    order := ParcelOrder{
        DeliveryAddress: "dummy address",
        PickupAddress:   "dummy pickup address",
        OrderID:         "unique-order-id-1",
        SenderId:        1,
        ParcelOrderDetails: &ParcelOrderDetails{
            Status: 0,
        },
    }
    DB.Create(&order)
}

日志记录:

2021/11/23 20:57:53 D:/go/src/udemy-solving/00003/main.go:62
[0.780ms] [rows:1] INSERT INTO `parcel_order_details` (`created_at`,`updated_at`,`deleted_at`,`biker_id`,`parcel_order_id`,`pickup_time`,`delivery_time`,`status`) VALUES ('2021-11-23 20:57:53.393','2021-11-23 20:57:53.393',NULL,NULL,4,NULL,NULL,0) ON DUPLICATE KEY UPDATE `parcel_order_id`=VALUES(`parcel_order_id`)

2021/11/23 20:57:53 D:/go/src/udemy-solving/00003/main.go:62
[14.900ms] [rows:1] INSERT INTO `parcel_orders` (`created_at`,`updated_at`,`deleted_at`,`sender_id`,`order_id`,`pickup_address`,`delivery_address`) VALUES ('2021-11-23 20:57:53.392','2021-11-23 20:57:53.392',NULL,1,'unique-order-id-1','dummy pickup address','dummy address')