Your Question
Before I report a bug I wanted to check if my expectation is correct.
I have a reproducer here that sets up some Models with a 1-to-many Foreign Key.
=UNSCOPED LOAD====================
2023/02/13 19:08:53 /...../gorm-playground/main_test.go:44
[0.162ms] [rows:0] SELECT * FROM `addresses` WHERE `addresses`.`id` = 1 AND `addresses`.`deleted_at` IS NULL
The store and fetch works fine however if I (soft) delete the children I am unable to load the compete model back with unscoped.
I was hoping (or expecting) unscoped to allow retrieval of the whole model including soft deleted children.
The document you expected this should be explained
https://gorm.io/docs/delete.html#Soft-Delete
Expected answer
Am I doing it wrong, or is it a bug? I see there have been various issues with soft delete/PreLoad/Joins in the past.
Comment From: manstis
The reproducer contains the complete code.
Models
type People []Person
type Person struct {
gorm.Model
AddressID *int
Address Address
}
type Address struct {
gorm.Model
AddressType string
AddressLines []AddressLine `gorm:"foreignKey:AddressID"`
}
type AddressLine struct {
AddressID *int `gorm:"primaryKey;index"`
Text string `gorm:"primaryKey;not null"`
}
Setup
Person{
Address: Address{
AddressType: "home",
AddressLines: []AddressLine{{
Text: "Line1",
},
{
Text: "Line2",
}},
},
}
Delete the address
DB.Delete(&result[0].Address)
// Try to load the _whole_ model (ignoring soft-deletes)
DB.Unscoped().Preload("Address.AddressLines").Find(&result2).Joins("Address").Joins("AddressLine")
Result Address model is missing.
[
{
"ID": 1,
"CreatedAt": "2023-02-13T19:30:25.933999285Z",
"UpdatedAt": "2023-02-13T19:30:25.933999285Z",
"DeletedAt": null,
"AddressID": 1,
"Address": {
"ID": 0,
"CreatedAt": "0001-01-01T00:00:00Z",
"UpdatedAt": "0001-01-01T00:00:00Z",
"DeletedAt": null,
"AddressType": "",
"AddressLines": null
}
}
]
Comment From: manstis
A potential fix is to ensure the preloadDB created to pre-load tables inherits the Unscoped setting from the main DB.
gorm/callbacks/query.go
...
//[L#250](https://github.com/go-gorm/gorm/blob/master/callbacks/query.go#L250)
preloadDB := db.Session(&gorm.Session{Context: db.Statement.Context, NewDB: true, SkipHooks: db.Statement.SkipHooks, Initialized: true})
db.Statement.Settings.Range(func(k, v interface{}) bool {
preloadDB.Statement.Settings.Store(k, v)
return true
})
// [manstis] Inherit Unscoped setting from parent DB
preloadDB.Statement.Unscoped = db.Statement.Unscoped
...
IDK the codebase well enough to suggest is this is the correct fix.
Comment From: a631807682
@manstis Would you like to create a PR for this?
Comment From: manstis
Yes, sure. I'll do a PR.
Comment From: manstis
See https://github.com/go-gorm/gorm/pull/6058
Comment From: manstis
PR merged into master. Closing.