go-gorm / gorm

The fantastic ORM library for Golang, aims to be developer friendly
https://gorm.io
MIT License
36.6k stars 3.91k forks source link

AutoMigrate foreign keys #450

Closed nkovacs closed 4 years ago

nkovacs commented 9 years ago

How do I create foreign keys with AutoMigrate?

type TestRun struct {
    ID        uint64
    StartedAt int64
    EndedAt   int64
    Suites    []Suite
}

type Suite struct {
    ID        uint64
    TestRunID uint64
    Name      string
}

db.AutoMigrate(&TestRun{}, &Suite{})
robvdl commented 5 years ago

If you plan to review the documentation, another real "gotcha" moment you get from using gorm is soft deletes. The docs go on to say you can use the Model base class for your models as I recall (using struct embedding), but it doesn't go on to say that this adds both a created_at and deleted_at column to each table. I don't mind a created_at column as it's useful for debugging, but deleted_at is a pretty bad default to have as it does soft deletes. e.g. marking the item as deleted but not really deleting it.

Soft deletes make querying harder as now in each query you have to filter your table queries as SELECT where NOT deleted_at etc... which is just another thing to remember.

I don't like soft deletes one bit, but mostly I think it needs to be extremely clear in the documentation that the author has made this decision to use soft deletes, and how to get out of using them.

Personally, when I was using gorm, I created my own model base class (struct) that only has the created_at field, therefore it won't use the soft delete functionality I dislike so much.

goldyfruit commented 5 years ago

I spent 3 hours looking for why my foreign key was not created using AutoMigrate().

As mentioned few times above, just a warning in the documentation saying that foreign keys are not supported and should be created with AddForeignKey() will be enough so far.

It's also possible to do this to add foreign key during the AutoMigrate():

db.AutoMigrate(Event{}).AddForeignKey("user_id", "users(id)", "RESTRICT", "RESTRICT")

Thanks for the hard work @jinzhu, it's really appreciate !

muety commented 5 years ago

I spent an hour to find out why FKs are not getting created until I found this issue. Thanks @goldyfruit, that solution works.

ghost commented 5 years ago

thanks @goldyfruit for the solution, initially proposed by @nkovacs and thanks @jinzhu for the amazing work you have done till now. I would like to contribute, starting with this issue, but I'm still a newbie with GoLang (i used to be a Django backend developer)

sentriz commented 5 years ago

hmm AddForeignKey() uses ALTER TABLE _ ADD CONSTRAINT which is not supported by sqlite

EDIT I found this comment helpful

ahmedkamalio commented 5 years ago

Okay, solution mentioned by @goldyfruit works but I'm getting an error every time I call AddForeignKey since the foreign key already exists and that's VERY annoying, is there any updates or upcoming updates?

0xp3p3 commented 5 years ago
package main

import (
    "fmt"

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

// File represents file
type File struct {
    Csurrogat int `gorm:"primary_key"`
    Name      string
    Positions []Position `gorm:"foreignkey:cfilesur;association_foreignkey:csurrogat"`
}

// Position represents position
type Position struct {
    Csurrogat int `gorm:"primary_key"`
    Cfilesur  int `sql:"type:integer REFERENCES files(csurrogat)"`
    Name      string
}

func main() {
    var err error
    var db *gorm.DB

    db, err = gorm.Open("sqlite3", "sample.db")
    if err != nil {
        panic("failed to connect sqlite database")
    }
    defer db.Close()

    // Migrate the schema
    db.AutoMigrate(&File{})
    db.AutoMigrate(&Position{})

    db.Create(&File{Csurrogat: 1, Name: "sample"})
    db.Create(&Position{Csurrogat: 1, Cfilesur: 1, Name: "file1"})
    db.Create(&Position{Csurrogat: 2, Cfilesur: 1, Name: "file2"})
    db.Create(&Position{Csurrogat: 3, Cfilesur: 1, Name: "file3"})

    files := []*File{}
    if err := db.Find(&files).Error; err != nil {
        panic(err)
    }

    for _, file := range files {
        db.Model(&file).Related(&file.Positions)
        fmt.Println(file.Positions)
    }

    fmt.Println(files[0])
}

This is not working at all. it is showing empty array for positions.

[] &{1 sample []}

What is wrong?

rvarner commented 4 years ago

This issue has been open for 4 years 9 months 3 days 17 hours 36 minutes. Can we get an update please?

jessequinn commented 4 years ago

lol. another issue is pointed here and yet it isnt resolved.

Any progress on this basic fundamental aspect?

jinzhu commented 4 years ago

@rvarner @jessequinn done in v2

LaysDragon commented 4 years ago

hi @jinzhu did you mean AutoMigrate can manage foreign keys in gorm v2?

jinzhu commented 4 years ago

@LaysDragon yes.

pkaramol commented 4 years ago

How do we explicitly use v2?

When importing

"github.com/jinzhu/gorm/v2"

I get the error message

| main.go:9:2: module github.com/jinzhu/gorm@latest found (v1.9.12), but does not contain package github.com/jinzhu/gorm/v2

GrigoriyMikhalkin commented 4 years ago

@pkaramol Just install it with go get github.com/jinzhu/gorm@v2_dev.

Also, it's currently in development, and as you can see, keeps same module name(i.e. without /v2 suffix). So you need to import it as github.com/jinzhu/gorm (or use replace directive in your local go.mod if, still, you want to import it as github.com/jinzhu/gorm/v2)