1
votes

I want to create a model User and Social where the User model has many Socials. Ideally a Social type would also have has one relation to simpilify querying from either side. Here is a code sample:

database type is MySQL 8.0

type base struct {
    ID         string    `json:"id" gorm:"type:char(36);primaryKey;"`
    Created    time.Time `json:"created" gorm:"autoCreateTime"`
    Updated    time.Time `json:"updated" gorm:"autoUpdateTime"`
}

type User struct {
    base
    Friends []*User      `json:"friends" gorm:"many2many:friends"`
    Socials []*Social    `json:"socials"`
}

type Social struct {
    base
    Provider   string `json:"provider" gorm:"type:varchar(32);index"`
    Identifier string `json:"identifier" gorm:"type:varchar(32);index"`
    User      *User   `json:"user" gorm:"foreignKey:ID"`
    Token      string `json:"token"`
    Link       string `json:"link" gorm:"type:varchar(128)"`
}

Im getting the following error when using db.AutoMigrate(&User{}, &Social{}):

model.Social's field User, need to define a valid foreign key for relations or it need to implement the Valuer/Scanner interface
runtime error: invalid memory address or nil pointer dereference

I have tried:

  • adding gorm:"foreignKey:ID" to User.Socials tags
  • not using pointers (eg in User struct Socials []Social instead of Socials []*Social)

but the issue remains

2

2 Answers

0
votes

According to documentation (https://gorm.io/docs/has_many.html#Has-Many), you need to use objects, not references


type User struct {
    base
    Friends []User      `json:"friends" gorm:"many2many:friends"`
    Socials []Social    `json:"socials"`
}

no * here

Also you can add UserID field to Social

type Social struct {
    base
    UserID string
    Provider   string `json:"provider" gorm:"type:varchar(32);index"`
    Identifier string `json:"identifier" gorm:"type:varchar(32);index"`
    User      *User   `json:"user" gorm:"foreignKey:ID"`
    Token      string `json:"token"`
    Link       string `json:"link" gorm:"type:varchar(128)"`
}

and add


type User struct {
    base
    FriendOf string      `gorm:""`
    Friends []*User      `json:"friends" gorm:"many2many:friends,foreignKey:FriendOf"`
    Socials []*Social    `json:"socials"`
}

0
votes

Issue was here:

type base struct {
    ...
}

type User {
    base
    ...
}

type Social {
    base
    ...
}

Since I thought base would just be package local definition I messed up the capitalization and had a private primary key.

Another issue was touched on by @vodolaz095, but (imo) not sufficiently clarified for any new go-gorm user.

It does not seem to be possible to use a has one relation like User User be the foreign key for a has many relation like Socials []Social gorm:"foreignKey:User". It is required to be split up as @vodolaz095 displayed in his 2nd code block