Gorm: Custom keys for many2many associations not working

Created on 2 May 2016  路  4Comments  路  Source: go-gorm/gorm

In a scenario as follows that features many-to-many relationships but using custom keys I expected gorm to make use of the specified ForeignKey and AssociationForeignKey. The keys are specified the same way as in multi_primary_keys_test.go, yet they seem to get ignored.

type Foo struct {
    ID    int64 `gorm:"primary_key"`
    Title string

    // Note the custom_bar_id and custom_foo_id which are ignored by GORM.
    AllocatedBars []*Bar `gorm:"many2many:foo_allocated_bars;ForeignKey:id,custom_bar_id;AssociationForeignKey:id,custom_foo_id"`
}

type Bar struct {
    ID int64 `gorm:"primary_key"`
}

Note: The full example source is available as a gist.

Expected Result

With the ForeignKey:id,custom_bar_id;AssociationForeignKey:id,custom_foo_id" keys defined gorm should be using custom_bar_id and custom_foo_id in the association table foo_allocated_bars.

Actual Result

Gorm ignores the keys altogether and creates default key names from the types table name, foo_id and bar_id.

This may be related to issue #955.

Most helpful comment

m2m doesn't support customize foreign keys in the join table rightnow, the tag ForeignKey:id,locale here means Blog having two foreign keys (ID, Locale)

If you really want to customize the column names in the join table, you could have a JoinModel, and customize its columns like below:

package main

import (
    "fmt"

    _ "github.com/go-sql-driver/mysql"
    "github.com/jinzhu/gorm"
    _ "github.com/lib/pq"
    _ "github.com/mattn/go-sqlite3"
)

var db *gorm.DB

type Foo struct {
    ID    int64 `gorm:"primary_key"`
    Title string

    // Note the custom_bar_id and custom_foo_id which are ignored by GORM.
    FooBars []FooBar
}

type FooBar struct {
    FooID uint `gorm:"column:custom_foo_id"`
    BarID uint `gorm:"column:custom_bar_id"`
    Bar   Bar
}

type Bar struct {
    ID   int64 `gorm:"primary_key"`
    Name string
}

func main() {
    // db, _ = gorm.Open("postgres", fmt.Sprintf("user=gorm password=gorm DB.name=gorm sslmode=disable"))
    // db, _ = gorm.Open("mysql", fmt.Sprintf("user=gorm password=gorm DB.name=gorm sslmode=disable"))
    db, _ = gorm.Open("sqlite3", "gorm.db")
    db.LogMode(true)
    db.DropTableIfExists(&Foo{}, &FooBar{}, &Bar{})
    db.AutoMigrate(&Foo{}, &FooBar{}, &Bar{})

    foo := Foo{
        Title:   "foo",
        FooBars: []FooBar{{Bar: Bar{Name: "bar"}}, {Bar: Bar{Name: "bar2"}}},
    }
    db.Save(&foo)

    var foo2 Foo
    db.Preload("FooBars.Bar").First(&foo2)
    fmt.Printf("%+v \n", foo2)
}

All 4 comments

+1

Just hacked my workaround into my local model_struct (for the exact same use case as yours it seems):

joinTableDBName := ToDBName(reflectType.Name()) + "_" + foreignField.DBName
if len(foreignKeys) >= 2 {
   joinTableDBName = foreignKeys[len(foreignKeys)-1]
}

I know that that's not a permanent, nor a pretty solution but it fixes the problem for me.

We just spent a while dealing with this issue as well. Any updates from the maintainers? @jinzhu

m2m doesn't support customize foreign keys in the join table rightnow, the tag ForeignKey:id,locale here means Blog having two foreign keys (ID, Locale)

If you really want to customize the column names in the join table, you could have a JoinModel, and customize its columns like below:

package main

import (
    "fmt"

    _ "github.com/go-sql-driver/mysql"
    "github.com/jinzhu/gorm"
    _ "github.com/lib/pq"
    _ "github.com/mattn/go-sqlite3"
)

var db *gorm.DB

type Foo struct {
    ID    int64 `gorm:"primary_key"`
    Title string

    // Note the custom_bar_id and custom_foo_id which are ignored by GORM.
    FooBars []FooBar
}

type FooBar struct {
    FooID uint `gorm:"column:custom_foo_id"`
    BarID uint `gorm:"column:custom_bar_id"`
    Bar   Bar
}

type Bar struct {
    ID   int64 `gorm:"primary_key"`
    Name string
}

func main() {
    // db, _ = gorm.Open("postgres", fmt.Sprintf("user=gorm password=gorm DB.name=gorm sslmode=disable"))
    // db, _ = gorm.Open("mysql", fmt.Sprintf("user=gorm password=gorm DB.name=gorm sslmode=disable"))
    db, _ = gorm.Open("sqlite3", "gorm.db")
    db.LogMode(true)
    db.DropTableIfExists(&Foo{}, &FooBar{}, &Bar{})
    db.AutoMigrate(&Foo{}, &FooBar{}, &Bar{})

    foo := Foo{
        Title:   "foo",
        FooBars: []FooBar{{Bar: Bar{Name: "bar"}}, {Bar: Bar{Name: "bar2"}}},
    }
    db.Save(&foo)

    var foo2 Foo
    db.Preload("FooBars.Bar").First(&foo2)
    fmt.Printf("%+v \n", foo2)
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

easonlin404 picture easonlin404  路  3Comments

littletwolee picture littletwolee  路  3Comments

pjebs picture pjebs  路  3Comments

corvinusy picture corvinusy  路  3Comments

youtwo123 picture youtwo123  路  3Comments