Jobin
Jobin

Reputation: 8282

GORM One-to One mapping issue

I have a strange issue with GORM mapping , I have two struct like below.

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"`
}

I'm using the Mysql DB, when I try to create the orders it didn't create entries on second table. For creating, I'm using below codes

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

Also When I try fetch data from the table Im getting an error like below

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

My fetch code is like below. Fetch issue is very strange bcoz the alias is assigned as ParcelOrder so fields that are not identifying with that name , instead it still using parcel_orders actual table name

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

The DB is not created with Go application it with Laravel application. Im trying to read/write data to that database.

any idea ?

Upvotes: 0

Views: 448

Answers (1)

David Yappeter
David Yappeter

Reputation: 1612

The answer is simple yet tricky to be understood.

You just need to add change:

ParcelOrderDetails ParcelOrderDetails `gorm:"foreignKey:ParcelOrderID"`

into

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

The reason is ParcelOrderDetails will create a empty model (not null) everytime ParcelOrder is initialized, of course on some cases we don't intended to accidentally create ParcelOrderOrderDetails because it is an empty model, I think GORM handle this case.

So if you make it into *ParcelOrderOrderDetails, it will be nil by default, which mean GORM will not create ParcelOrderOrderDetails and vice versa.

This is my full code

// https://stackoverflow.com/questions/69977516/unsupported-relations-for-schema-with-has-many-relation-in-gorm/70082006#70082006
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)
}

Logging:

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')

Upvotes: 2

Related Questions