GORM Playground Link
go-gorm/playground#537
Description
User and UserProp models are saved independently in different API endpoints so they are not connected by a foreign key. But in another API endpoint they should load together so used Preload("UserProps") with multiple foreign keys to achieve this.
type Company struct {
ID int
Name string
}
type User struct {
gorm.Model
Name string
CompanyID *int
Company Company
ManagerID *uint
Manager *User
UserProps *UserProp `gorm:"foreignkey:CompanyID,ManagerID;references:CompanyID,ManagerID"`
}
type UserProp struct {
ID int
CompanyID int
ManagerID uint
Value string
}
Expected
UserProp and User connects by CompanyID and ManagerID. Since those fields are nullable in User model it leads to User.UserProps emptiness.
company := &Company{Name: "ACME"}
DB.Create(company)
user := &User{
Name: "manager",
CompanyID: &company.ID,
// have no manager
ManagerID: nil,
}
DB.Create(user)
var resultUser User
DB.Preload("UserProps").First(&resultUser, user.ID)
So, the following SQL is expected to be generated (will return 0 rows, and that's the idea: no panics):
SELECT * FROM "user_props" WHERE ("user_props"."company_id","user_props"."manager_id") IN ((1,NULL))
Actual
We got panic in case of one of values is NULL:
2022/10/24 09:42:39 testing postgres...
=== RUN TestGORM
2022/10/24 09:42:39 /mnt/c/Users/crab/Go Projects/gorm-playground/main_test.go:13
[3.820ms] [rows:1] INSERT INTO "companies" ("name") VALUES ('ACME') RETURNING "id"
2022/10/24 09:42:39 /mnt/c/Users/crab/Go Projects/gorm-playground/main_test.go:21
[2.940ms] [rows:1] INSERT INTO "users" ("created_at","updated_at","deleted_at","name","company_id","manager_id") VALUES ('2022-10-24 09:42:39.32','2022-10-24 09:42:39.32',NULL,'manager',1,NULL) RETURNING "id"
2022/10/24 09:42:39 /mnt/c/Users/crab/Go Projects/gorm-playground/main_test.go:28
[2.340ms] [rows:1] INSERT INTO "users" ("created_at","updated_at","deleted_at","name","company_id","manager_id") VALUES ('2022-10-24 09:42:39.324','2022-10-24 09:42:39.324',NULL,'jinzhu',1,1) RETURNING "id"
2022/10/24 09:42:39 /mnt/c/Users/crab/Go Projects/gorm-playground/main_test.go:37
[2.806ms] [rows:1] INSERT INTO "user_props" ("company_id","manager_id","value") VALUES (1,1,'foo') RETURNING "id"
=== RUN TestGORM/user_has_props
2022/10/24 09:42:39 /mnt/c/Users/crab/Go Projects/gorm-playground/main_test.go:46
[0.578ms] [rows:1] SELECT * FROM "user_props" WHERE ("user_props"."company_id","user_props"."manager_id") IN ((1,1))
2022/10/24 09:42:39 /mnt/c/Users/crab/Go Projects/gorm-playground/main_test.go:46
[1.575ms] [rows:1] SELECT * FROM "users" WHERE "users"."id" = 2 AND "users"."deleted_at" IS NULL ORDER BY "users"."id" LIMIT 1
=== RUN TestGORM/user_without_props
--- FAIL: TestGORM (0.02s)
--- PASS: TestGORM/user_has_props (0.00s)
--- FAIL: TestGORM/user_without_props (0.00s)
panic: reflect: call of reflect.Value.Interface on zero Value [recovered]
panic: reflect: call of reflect.Value.Interface on zero Value
goroutine 16 [running]:
testing.tRunner.func1.2({0xce5dc0, 0xc0000142b8})
/usr/local/go/src/testing/testing.go:1209 +0x36c
testing.tRunner.func1()
/usr/local/go/src/testing/testing.go:1212 +0x3b6
panic({0xce5dc0, 0xc0000142b8})
/usr/local/go/src/runtime/panic.go:1047 +0x266
reflect.valueInterface({0x0, 0x0, 0x0}, 0x1)
/usr/local/go/src/reflect/value.go:1356 +0x21e
reflect.Value.Interface(...)
/usr/local/go/src/reflect/value.go:1351
...
created by testing.(*T).Run
/usr/local/go/src/testing/testing.go:1306 +0x727
FAIL gorm.io/playground 0.102s
FAIL
GORM Playground Link
go-gorm/playground#537
Description
UserandUserPropmodels are saved independently in different API endpoints so they are not connected by a foreign key. But in another API endpoint they should load together so usedPreload("UserProps")with multiple foreign keys to achieve this.Expected
UserPropandUserconnects byCompanyIDandManagerID. Since those fields are nullable inUsermodel it leads toUser.UserPropsemptiness.So, the following SQL is expected to be generated (will return 0 rows, and that's the idea: no panics):
Actual
We got panic in case of one of values is NULL: