First, database is created with sqlite3 test.db < schema.sql.
Contents of schema.sql:
CREATE TABLE x (
id INTEGER PRIMARY KEY,
name TEXT
);
CREATE TABLE y (
id INTEGER PRIMARY KEY,
name TEXT,
x_id INTEGER REFERENCES x
);
Then the program is run with go run main.go.
Contents of main.go:
package main
import (
"gorm.io/gorm"
"gorm.io/driver/sqlite"
)
type X struct {
ID uint
Name string
Ys []*Y
}
type Y struct {
ID uint
Name string
X *X `gorm:"column:x_id"`
}
func (X) TableName() string {
return "x"
}
func (Y) TableName() string {
return "y"
}
func main() {
db, _ := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
x := &X{Name: "X"}
y := &Y{Name: "Y", X: x}
x.Ys = []*Y{y}
db.Create(&x)
}
After which fatal error: stack overflow is thrown.
I guess it has something to do with the recursive nature of the structs and objects involved. When I comment out the Ys []*Y line along with y := &Y{Name: "Y", X: x} and x.Ys = []*Y{y} it successfully inserts "X" into table x, but when I comment out the Ys []*Y and x.Ys = []*Y{y} only and change db.Create(&x) to db.Create(&y) nothing gets inserted in either table.
EDIT
It saves x and y when y := &Y{Name: "Y", X: x} is changed to y := &Y{Name: "Y"}, but with x_id as NULL.
CodePudding user response:
The issue is indeed with the recursive nature of the relations: X contains []Y, and Y contains X.
As explained in documentation, the has-many relation is modeled simply using uint for the foreign key column:
type X struct {
ID uint
Name string
Ys []*Y `gorm:"foreignKey:XID"`
}
type Y struct {
ID uint
Name string
XID uint `gorm:"column:x_id"`
}
And you don't need to set y.XID, it will be filled automatically.
CodePudding user response:
Implementing Valuer interface did the trick.
func (x X) Value() (driver.Value, error) {
return int64(x.ID), nil
}
