为什么变量没有被覆盖?

huangapple go评论86阅读模式
英文:

Why isn't the variable overwritten?

问题

如果你这样写:

func showAll(db *gorm.DB) {
   users := &[]models.User{}
   card := models.Card{}
   db.Find(users)
   for _, i := range *users {
      fmt.Println(i)

      db.Where("user_id = ?", i.ID).Find(&card)
      fmt.Println(card)
   }
}

那么fmt.Println(card)总是打印第一个值。
但是如果你这样写:

func showAll(db *gorm.DB) {
   users := &[]models.User{}
   
   db.Find(users)
   for _, i := range *users {
      fmt.Println(i)
      card := models.Card{}
      db.Where("user_id = ?", i.ID).Find(&card)
      fmt.Println(card)
   }
}

它会正确打印。为什么?难道不应该覆盖&card变量吗?

我想打印出找到的所有用户的所有卡片。

英文:

If you write it this way

func showAll(db *gorm.DB) {
   users := &[]models.User{}
   card := models.Card{}
   db.Find(users)
   for _, i := range *users {
      fmt.Println(i)

      db.Where("user_id = ?", i.ID).Find(&card)
      fmt.Println(card)
   }
}

then fmt.Println(card) always prints the first value.
But if you write it this way

func showAll(db *gorm.DB) {
   users := &[]models.User{}
   
   db.Find(users)
   for _, i := range *users {
      fmt.Println(i)
      card := models.Card{}
      db.Where("user_id = ?", i.ID).Find(&card)
      fmt.Println(card)
   }
}

It prints correctly. Why? Shouldn't the &card variable be overwritten?

I wanted to print all the cards for found users.

答案1

得分: 2

你的第一个问题是你没有处理错误,如果你处理了错误,你就会知道第一个查询之后的所有查询都会导致记录未找到。你的第二个问题是你似乎不知道 gorm 有调试功能,如果你打开它,它会显示生成的 SQL,如果你查看它,你会立即发现问题所在。最后,你的实际问题是在第一次迭代之后,card 结构体实例具有非零的 ID,这与显式的 i.ID 一起在 WHERE 子句中被使用。

所以,除非 i.IDcard.ID 是相同的(或者 card.ID 是零),否则:

db.Where("user_id = ?", i.ID).Find(&card).Error == ErrRecordNotFound

https://gorm.io/docs/query.html#String-Conditions

如果对象的主键已经设置,那么条件查询不会涵盖主键的值,而是将其作为“and”条件使用。例如:

var user = User{ID: 10}
db.Where("id = ?", 20).First(&user)
// SELECT * FROM users WHERE id = 10 and id = 20 ORDER BY id ASC LIMIT 1

这个查询会导致记录未找到的错误。所以在你想要使用变量(比如 user)从数据库获取新值之前,将主键属性(比如 id)设置为 nil。

英文:

Your first problem is that you aren't handling errors, if you were then you would know that all queries after the first one result in record-not-found. Second of your problems is the fact that you don't seem to be aware that gorm has debugging which, if you turn it on, will show the generated SQL and if you were to look at that you would immediately spot what's wrong. Finally, your actual problem, is the fact that after the first iteration the card struct instance has a non-zero ID which, alongside the explicit i.ID is also used in the WHERE clause.

So unless i.ID and card.ID are identical (or card.ID is zero) then:

db.Where("user_id = ?", i.ID).Find(&card).Error == ErrRecordNotFound

https://gorm.io/docs/query.html#String-Conditions

> If the object’s primary key has been set, then condition query wouldn’t cover the value of primary key but use it as a ‘and’ condition. For example:
>
> go
> var user = User{ID: 10}
> db.Where("id = ?", 20).First(&user)
> // SELECT * FROM users WHERE id = 10 and id = 20 ORDER BY id ASC LIMIT 1
>

>
> This query would give record not found Error. So set the primary key attribute such as id to nil before you want to use the variable such as user to get new value from database.

huangapple
  • 本文由 发表于 2022年12月26日 00:46:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/74914610.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定