1 回答

TA貢獻1796條經驗 獲得超4個贊
您看到的 Insert 語句實際上是 Upsert 語句,您會注意到在插入部分之后,它們具有 ON CONFLICT 子句。如果主鍵已經在表中(即存在鍵沖突,因此得名),則這樣做就是更新記錄。按預期工作也是如此。Updates
但!
還有一個問題。就目前而言,這些語句仍會導致將新關系和新地址插入到數據庫中,因為不會有主鍵沖突。這是因為您尚未為“關系”或“地址”行輸入主鍵(您將看到插入中沒有列)。id
經驗法則:
Gorm 將主鍵為零的結構視為新行,并在保存時插入它們。推論:您只能更新具有非零主鍵的結構。
您可能認為您在調用中提供了主鍵,但這僅適用于頂級結構。當 gorm 處理關系時,它看不到任何主鍵,并假定您要添加新關系,而不是更新現有關系。Where
如果你考慮一下,這是有道理的:如果你不提供 Relation.ID,gorm怎么知道哪個關系目前與公司有關。知道這一點的方法是首先使用OwnerID和OwnerType進行選擇以找出答案,但這不是gorm會為您做的事情(gorm通常試圖做到極簡主義,并且不會嘗試自己找到比您提供的信息更多的信息)。
解決此問題的一種簡單方法是讓您的API用戶在輸入中提供 Relation.ID 和Address.ID,但在這種情況下,這是非常不方便的。
我發現解決此問題的一個很好的模式是首先加載目標根對象的當前狀態以及要更新的相關關系,然后將來自API用戶的更改應用于結構和關系,然后使用。這將保存所有字段,無論它們是否已更改。Save
另一種選擇是將關系的現有 ID 放入您從 DB 中提取的版本,然后像您在此處所做的那樣調用。update.Relation.ID
update.Relation.Addresses[i].ID
Updates
獎勵:HasMany有更多的更新挑戰
對于“地址”,需要特別注意,因為它是一個 HasMany 關系。當調用gorm永遠不會刪除關系時,例如,當您之前有3個地址并且現在只想擁有兩個地址時,它只會更新其中兩個地址,而第三個地址則懸而未決;這是為了防止錯誤地刪除數據。相反,你必須明確你的意圖。Save/Updates
然后,您要做的是使用關聯模式來替換關聯,但是在調用 :Updates
tx := db.Begin()
// do your thing
err := tx.
Session(&gorm.Session{FullSaveAssociations: true}).
Where("id = ?", id).
Omit("Relation.Addresses")
Updates(update).
Error
if err != nil {
tx.Rollback()
// handle error
}
// assuming update.Relation.ID is set
err = tx.
Model(&update.Relation).
Association("Addresses").
Replace(&update.Relation.Addresses)
if err != nil {
tx.Rollback()
// handle error
}
if err := tx.Commit().Error; err != nil {
tx.Rollback()
// handle error
}
- 1 回答
- 0 關注
- 145 瀏覽
添加回答
舉報