Обратный поиск внешнего ключа в GORM - PullRequest
0 голосов
/ 06 января 2020

Я пытаюсь реализовать пример ассоциации «Имеет много» из GORM (https://gorm.io/docs/has_many.html#Has -Many ), в котором User может иметь много CreditCard s:

package main

import (
    "fmt"
    "os"

    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/sqlite"
    "github.com/sirupsen/logrus"
)

type User struct {
    gorm.Model
    CreditCards []CreditCard
}

type CreditCard struct {
    gorm.Model
    Number string
    UserID uint
}

const dbName = "examplegorm.db"

func main() {
    db, err := gorm.Open("sqlite3", dbName)
    if err != nil {
        logrus.Fatalf("open db: %v", err)
    }
    defer func() {
        db.Close()
        os.Remove(dbName)
    }()

    db.LogMode(true)
    db.AutoMigrate(&User{})
    db.AutoMigrate(&CreditCard{})

    user := User{}
    if err := db.Create(&user).Error; err != nil {
        logrus.Errorf("create user: %v", err)
    }

    fmt.Println(user.CreditCards)

    creditCard := CreditCard{Number: "42", UserID: user.ID}
    if err := db.Create(&creditCard).Error; err != nil {
        logrus.Errorf("create credit card: %v", err)
    }

    db.First(&user, user.ID)
    fmt.Println(user.CreditCards)
}

Я ожидал бы, что поле CreditCards будет автоматически обновлено с CreditCard объектами с этим UserID, но если я запустите этот скрипт, я вижу, что user.CreditCards - это пустой срез как до, так и после добавление кредитной карты:

kurt@Kurts-MacBook-Pro-13 ~/D/Scratch> go run gorm_has_many.go 

(/Users/kurt/Documents/Scratch/gorm_has_many.go:36) 
[2020-01-06 11:11:56]  [0.88ms]  CREATE TABLE "users" ("id" integer primary key autoincrement,"created_at" datetime,"updated_at" datetime,"deleted_at" datetime )  
[0 rows affected or returned ] 

(/Users/kurt/Documents/Scratch/gorm_has_many.go:36) 
[2020-01-06 11:11:56]  [0.65ms]  CREATE INDEX idx_users_deleted_at ON "users"(deleted_at)   
[0 rows affected or returned ] 

(/Users/kurt/Documents/Scratch/gorm_has_many.go:37) 
[2020-01-06 11:11:56]  [0.57ms]  CREATE TABLE "credit_cards" ("id" integer primary key autoincrement,"created_at" datetime,"updated_at" datetime,"deleted_at" datetime,"number" varchar(255),"user_id" integer )  
[0 rows affected or returned ] 

(/Users/kurt/Documents/Scratch/gorm_has_many.go:37) 
[2020-01-06 11:11:56]  [0.55ms]  CREATE INDEX idx_credit_cards_deleted_at ON "credit_cards"(deleted_at)   
[0 rows affected or returned ] 

(/Users/kurt/Documents/Scratch/gorm_has_many.go:40) 
[2020-01-06 11:11:56]  [0.21ms]  INSERT  INTO "users" ("created_at","updated_at","deleted_at") VALUES ('2020-01-06 11:11:56','2020-01-06 11:11:56',NULL)  
[1 rows affected or returned ] 
[]

(/Users/kurt/Documents/Scratch/gorm_has_many.go:47) 
[2020-01-06 11:11:56]  [0.23ms]  INSERT  INTO "credit_cards" ("created_at","updated_at","deleted_at","number","user_id") VALUES ('2020-01-06 11:11:56','2020-01-06 11:11:56',NULL,'42',1)  
[1 rows affected or returned ] 

(/Users/kurt/Documents/Scratch/gorm_has_many.go:51) 
[2020-01-06 11:11:56]  [0.15ms]  SELECT * FROM "users"  WHERE "users"."deleted_at" IS NULL AND "users"."id" = 1 AND (("users"."id" = 1)) ORDER BY "users"."id" ASC LIMIT 1  
[1 rows affected or returned ] 
[]

Как мне заполнить поле CreditCards? Разве это не должно происходить автоматически?

В отличие от этого, если у меня есть следующие модели Django (в приложении под названием djangoapp):

from django.db import models


class User(models.Model):
    name = models.CharField(max_length=255)
    age = models.PositiveIntegerField()


class CreditCard(models.Model):
    number = models.CharField(max_length=255)
    user = models.ForeignKey('djangoapp.User', on_delete=models.CASCADE)

, затем после добавления кредитной карты в пользователь, я могу получить user.creditcard_set (ср. https://docs.djangoproject.com/en/3.0/topics/db/examples/many_to_one/):

In [5]: user = User.objects.create(name="jinzhu", age=20)                                             
(0.002) INSERT INTO "djangoapp_user" ("name", "age") VALUES ('jinzhu', 20); args=['jinzhu', 20]

In [6]: credit_card = CreditCard.objects.create(number="42", user=user)                               
(0.002) INSERT INTO "djangoapp_creditcard" ("number", "user_id") VALUES ('42', 3); args=['42', 3]

In [8]: user.creditcard_set.all()                                                                     
Out[8]: (0.000) SELECT "djangoapp_creditcard"."id", "djangoapp_creditcard"."number", "djangoapp_creditcard"."user_id" FROM "djangoapp_creditcard" WHERE "djangoapp_creditcard"."user_id" = 3 LIMIT 21; args=(3,)
<QuerySet [<CreditCard: CreditCard object (1)>]>

Если CreditCards в этом примере не эквивалентно Django s creditcard_set?

Ответы [ 2 ]

1 голос
/ 07 января 2020

Вам нужно Preload CreditCards, чтобы получить их при запросе. Например.

var user User
db.Preload("CreditCards").First(&user)

Подробнее об этом здесь: http://gorm.io/docs/preload.html

1 голос
/ 06 января 2020

Я обошел это, просто выполнив запрос, который Django s creditcard_set делает под капотом:

var creditCards []CreditCard
if err := db.Where("user_id = ?", user.ID).Find(&creditCards).Error; err != nil {
    logrus.Errorf("get credit cards for user: %v", err)
}

Я все еще немного озадачен, какая цель User.CreditCards поле в примере документации GORM.

...