亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Updates() 似乎沒有更新關聯

Updates() 似乎沒有更新關聯

Go
白衣染霜花 2022-08-01 16:32:24
我有以下結構。type Relation struct {    gorm.Model    OwnerID      uint          `json:"ownerID"`    OwnerType    string        `json:"ownerType"`    Addresses    []Address     `gorm:"polymorphic:Owner;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"addresses"`}type Company struct {    gorm.Model    Name     string   `json:"name"`    Relation Relation `gorm:"polymorphic:Owner;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"relation"`}type Address struct {    gorm.Model    OwnerID   uint   `json:"ownerID"`    OwnerType string `json:"ownerType"`    Country   string `json:"country"`    Zip       string `json:"zip"`    Number    uint   `json:"number,string"`    Addition  string `json:"addition"`    Street    string `json:"street"`    State     string `json:"state"`    City      string `json:"city"`}以及以下處理程序func UpdateCompany(db *database.Database) fiber.Handler {    return func(c *fiber.Ctx) error {        id, err := IDFromParams(c)        if err != nil {            return c.JSON(responseKit.ParameterMissing())        }        update := new(model.Company)        if err = json.Unmarshal(c.Body(), update); err != nil {            return c.JSON(responseKit.ParsingError())        }        if result := db.Session(&gorm.Session{FullSaveAssociations: true}).Where("id = ?", id).Debug().Updates(update); result.Error != nil {            return c.JSON(responseKit.RecordUpdateError())        }        updated := new(model.Company)        result := db.Preload("Relation.Addresses").            Find(updated, id)        if result.Error != nil {            return c.JSON(responseKit.RecordReadError())        }        return c.JSON(responseKit.RecordUpdatedSuccess(updated))    }}我讀了https://gorm.io/docs/associations.html和https://github.com/go-gorm/gorm/issues/3487#issuecomment-698303344但它似乎不起作用。我使用 rest 客戶端使用以下 JSON 調用終結點{    "name": "yep",    "relation": {        "adresses": [            {                "number": "5"            }        ]    }}
查看完整描述

1 回答

?
慕的地8271018

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.IDupdate.Relation.Addresses[i].IDUpdates

獎勵: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

}


查看完整回答
反對 回復 2022-08-01
  • 1 回答
  • 0 關注
  • 145 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號