Ассоциация GORM «Имеет много» не создает внешний ключ? - PullRequest
0 голосов
/ 06 января 2020

Следуя примеру в документации GORM (http://gorm.io/docs/has_many.html#Has -Много ), я попытался создать модель User и CreditCard с отношением один-ко-многим:

package main

import (
    "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
}

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

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

Тем не менее, в результирующих записанных SQL операторах я не вижу ничего похожего на

CREATE TABLE credit_cards(
    ...
    FOREIGN KEY(user_id) REFERENCES users(id)
)

, как я ожидал бы из документации SQLite (https://www.sqlite.org/foreignkeys.html). Я вижу

> go run gorm_has_many.go

(/Users/kurt/Documents/Scratch/gorm_has_many.go:28) 
[2020-01-06 09:05:58]  [0.82ms]  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:28) 
[2020-01-06 09:05:58]  [0.55ms]  CREATE INDEX idx_users_deleted_at ON "users"(deleted_at)   
[0 rows affected or returned ] 

(/Users/kurt/Documents/Scratch/gorm_has_many.go:29) 
[2020-01-06 09:05:58]  [0.52ms]  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:29) 
[2020-01-06 09:05:58]  [0.50ms]  CREATE INDEX idx_credit_cards_deleted_at ON "credit_cards"(deleted_at)   
[0 rows affected or returned ] 

Для сравнения, в примере проекта Django в приложении djangoapp, если у меня есть следующие models.py:

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)

и я Изучив операторы SQL, соответствующие созданию модели CreditCard, я вижу ссылку на внешний ключ:

kurt@Kurts-MacBook-Pro-13 ~/D/S/djangoproject> python manage.py sqlmigrate djangoapp 0002_creditcard
(0.000) 
            SELECT name, type FROM sqlite_master
            WHERE type in ('table', 'view') AND NOT name='sqlite_sequence'
            ORDER BY name; args=None
(0.000) SELECT "django_migrations"."id", "django_migrations"."app", "django_migrations"."name", "django_migrations"."applied" FROM "django_migrations"; args=()
(0.000) PRAGMA foreign_keys = OFF; args=None
(0.000) PRAGMA foreign_keys; args=None
(0.000) BEGIN; args=None
CREATE TABLE "djangoapp_creditcard" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "number" varchar(255) NOT NULL, "user_id" integer NOT NULL REFERENCES "djangoapp_user" ("id") DEFERRABLE INITIALLY DEFERRED); (params None)
(0.000) PRAGMA foreign_key_check; args=None
CREATE INDEX "djangoapp_creditcard_user_id_eca64c45" ON "djangoapp_creditcard" ("user_id"); (params ())
(0.000) PRAGMA foreign_keys = ON; args=None
BEGIN;
--
-- Create model CreditCard
--
CREATE TABLE "djangoapp_creditcard" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "number" varchar(255) NOT NULL, "user_id" integer NOT NULL REFERENCES "djangoapp_user" ("id") DEFERRABLE INITIALLY DEFERRED);
CREATE INDEX "djangoapp_creditcard_user_id_eca64c45" ON "djangoapp_creditcard" ("user_id");
COMMIT;

Почему столбец user_id не генерируется с предложением REFERENCES как в приложении Django? (Похоже, что в GORM есть метод addForeignKey() (https://github.com/jinzhu/gorm/blob/79a77d771dee4e4b60e9c543e8663bbc80466670/scope.go#L1229 -L1238 ), но в этом примере он не вызывается).

Обновление

Поскольку может показаться, что метод GORM AddForeignKey() на самом деле не вызывается внутри самой GORM, я добавил следующую строку:

db.Model(&CreditCard{}).AddForeignKey("user_id", "users(id)", "CASCADE", "CASCADE")

Однако при повторном запуске сценария появляется ошибка синтаксиса:

(/Users/kurt/Documents/Scratch/gorm_has_many.go:30) 
[2020-01-06 09:36:29]  near "CONSTRAINT": syntax error 

(/Users/kurt/Documents/Scratch/gorm_has_many.go:30) 
[2020-01-06 09:36:29]  [0.06ms]  ALTER TABLE "credit_cards" ADD CONSTRAINT credit_cards_user_id_users_id_foreign FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE;  
[0 rows affected or returned ] 

1 Ответ

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

Горм не добавляет иностранные ключи при автоматической миграции. Вы должны сделать это вручную.

SQLite не поддерживает добавление ограничений после создания таблицы. Вот почему у вас ошибка. Проверьте этот ресурс: Как добавить внешний ключ в существующую таблицу SQLite?

...