Reputation: 57611
Following an example in GORM's documentation (http://gorm.io/docs/has_many.html#Has-Many), I attempted to make a User
and CreditCard
model with a one-to-many relation:
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{})
}
However, in resulting logged SQL statements I don't see something like
CREATE TABLE credit_cards(
...
FOREIGN KEY(user_id) REFERENCES users(id)
)
as I would expect from SQLite's documentation (https://www.sqlite.org/foreignkeys.html). What I see is
> 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 ]
By contrast, in an example Django project in a djangoapp
app, if I have the following 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)
and I inspect the SQL statements corresponding to the creation of the CreditCard
model, I do see a foreign key reference:
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;
Why is the user_id
column not being generated with a REFERENCES
clause like in the Django app? (It seems that GORM has an addForeignKey()
method (https://github.com/jinzhu/gorm/blob/79a77d771dee4e4b60e9c543e8663bbc80466670/scope.go#L1229-L1238) but it isn't getting invoked in this example).
Since it would appear that GORM's AddForeignKey()
method doesn't actually get called within GORM itself, I added the following line:
db.Model(&CreditCard{}).AddForeignKey("user_id", "users(id)", "CASCADE", "CASCADE")
However, re-running the script then appears to show a syntax error:
(/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 ]
Upvotes: 0
Views: 1127
Reputation: 3795
Gorm does not add Foreign Keys when Auto Migrating. You gotta do it manually.
SQLite does not support adding constraints after creating the table. That's why the error you're having. Check this resource: How do I add a foreign key to an existing SQLite table?
Upvotes: 1