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.