Your Question

I want to select specific fields of User, so I defined a smaller struct called APIUser which can select specific fields automatically. Also I want preload Orders when find users.

type User struct {
  gorm.Model
  Name   string
  Age    int
  Gender string
  Orders []Order
}

type Order struct {
  gorm.Model
  UserID uint
  Price  float64
}

type APIUser struct {
  ID     uint
  Name   string
  Orders []Order
}

db.Model(&User{}).Preload("Orders").Find(&APIUser{})

When I run the above code, I get the following error.

[error] invalid field found for struct main.APIUser's field Orders, need to define a valid foreign key for relations or it need to implement the Valuer/Scanner interface
panic: reflect: call of reflect.Value.Field on uint Value

Is it impossible to use it this way?

The document you expected this should be explained

Expected answer

Comment From: jinzhu

db.Model(&User{}).Preload("Orders", func(tx gorm.DB) gorm.DB { return tx.Select("Name") }).Find(&APIUser{})

Comment From: wolfapple

@jinzhu

My question was not whether I can select fields when calling the Preload function, but how to use Preload on smaller struct for smart select fields.

After this and that experiment, the following results were obtained.

type User struct {
  gorm.Model
  Name   string
  Age    int
  Gender string
  Orders []Order
}

type Order struct {
  gorm.Model
  UserID uint
  Price  float64
}

type APIUser struct {
  ID     uint
  Name   string
  Orders []Order `gorm:"foreignKey:UserID"`
}

db.Model(&User{}).Preload("Orders").Find(&APIUser{}) // panic!
db.Table("users").Preload("Orders").Find(&APIUser{}) // it works, but smart select is not working!

Instead of using the Model function, I found that specifying the table name works. But smart select didn't work. I have confirmed that the following query is executed.

SELECT * FROM `orders` WHERE `orders`.`user_id` = 1 AND `orders`.`deleted_at` IS NULL
SELECT * FROM `users`

Since the APIUser structure only has an ID and a Name, the following query should be executed.

SELECT `users`.`id`,`users`.`name` FROM `users` WHERE `users`.`deleted_at` IS NULL

Comment From: vuhoanglam

I ran into the same problem, I think this is a bug

Comment From: therealpaulgg

I can confirm I have the exact same problem, panic and everything. Smart select works on anything that does not have associations, but if I try to preload and do associations there is a panic. This issue should be re-opened.

Comment From: fnsne

I met this problem too. When I using with the smart select field(like struct APIUser other mention above), I will panic. But when using with the model struct( like struct User above) the preload works well.

Comment From: fnsne

I think there is something not defined. Because when I change to using embedded, it works well.

I only change the APIUser to this.

type APIUser struct {
  gorm.Model
  Name   string
  Orders []Order `gorm:"foreignKey:ID"`
}

And the preload words well. db.Preload("Orders").Model(&User{}).Find(&APIUser{})

Comment From: wolfapple

@fnsne Have you tried testing even when data actually exists in the users table and the orders table? When there is no data, the panic does not occur as you said, but if there is data, it still panics.

Comment From: fnsne

@wolfapple I don't know how to execute the Find(&APIUser{}) with no data in the two tables. But I used the command above I wrote, it works with data in two tables. There is no panic. Maybe the version I'm using? I use v1.20.7.

Comment From: loeffel-io

This is amazing @jinzhu

db.Model(&User{}).Preload("Orders", func(tx *gorm.DB) *gorm.DB {
return tx.Select("Name")
}).Find(&APIUser{})

But how to do that with Joins?