【问题标题】:GORM: Updating inserts nested data instead of modifyingGORM:更新插入嵌套数据而不是修改
【发布时间】:2021-01-26 18:19:09
【问题描述】:

当我更新嵌套模型时,GORM 不会更新子模型,它会插入新的子模型并更新父模型。

我有一个相当简单的数据模型 我有一个基本模型

type Base struct {
    ID        string  `gorm:"primaryKey;unique;type:uuid;default:uuid_generate_v4();" json:"id"`
    CreatedAt time.Time `gorm:"type:timestamp without time zone;not null;"`
    UpdatedAt time.Time `gorm:"type:timestamp without time zone;not null;"`
}

**我里面只有Jinzhu(Gorm coder)的唯一标签,建议添加。我认为拥有主键就足够了。

我有一个客户模型

type ClientCustomer struct {
    Base
    Name          string
    Address       string
    Lat           float32
    Lon           float32
    ClientID      string `gorm:"type:uuid"`
    Contacts      []CustomerContact
}

我有一个联系人模型

type CustomerContact struct {
    Base
    Name             string `gorm:"not null"`
    Email            string
    Phone            string
    ContactTypeID    uint
    ClientCustomerID string `gorm:"type:uuid"`
    
}

客户与联系人具有一对多的关系。 当我想更新客户/客户联系人时,GORM 最终会插入一个新联系人并更新客户。我希望 GORM 更新这两个模型。

这是我要发送的 json:

{
    "id": "a375380a-0450-4670-8e23-9dc1d08249cd",
    "clientId": "d97a96ca-6b05-423a-814c-7c4ba2a5ebe4",
    "name": "Customer Name",
    "address": "Customer address",
    "lat": 0,
    "lon": 0,
    "sites": [],
    "customerContacts": [
        {
            "id": "39e78040-92a1-4834-aff6-ff64661c5d65",
            "name": "Jessica2",
            "email": "blah@blah.com",
            "phone": "555555555",
            "contactType": 1,
            "customerId": "a375380a-0450-4670-8e23-9dc1d08249cd",
            "clientId": "d97a96ca-6b05-423a-814c-7c4ba2a5ebe4"
        }
    ]
}

我要更新的代码是:

DB.Debug().Updates(updateData) => updateDate is a customer

我还尝试了以下方法:

DB.Debug().Save(updateData)
db.Session(&gorm.Session{FullSaveAssociations: true}).Updates(updateData)

它总是插入新的孩子 在 postgres 中查看我的表结构时,它正是它应该是的。 从联系人到客户有一个外键

我的想法不多了。

这是 GORM 的输出:

[1.319ms] [rows:1] INSERT INTO "customer_contacts" ("name","email","phone","contact_type_id","client_customer_id","created_at","updated_at","doppl_client_id","id") VALUES ('Jessica2','blah@blah.com','555555555',1,'a375380a-0450-4670-8e23-9dc1d08249cd','2021-01-26 18:12:05.744','2021-01-26 18:12:05.744','d97a96ca-6b05-423a-814c-7c4ba2a5ebe4','d749018f-5484-4308-a60d-3ef86a896a6b') ON CONFLICT ("id") DO UPDATE SET "client_customer_id"="excluded"."client_customer_id" RETURNING "id"


2021/01/26 18:12:05 /go/src/app/pkg/providers/gormRepository.go:120

[3.543ms] [rows:1] UPDATE "client_customers" SET "name"='Customer Name',"address"='Customer address',"doppl_client_id"='d97a96ca-6b05-423a-814c-7c4ba2a5ebe4',"updated_at"='2021-01-26 18:12:05.743' WHERE "id" = 'a375380a-0450-4670-8e23-9dc1d08249cd'

【问题讨论】:

    标签: go go-gorm


    【解决方案1】:

    Gorm 实际上正在运行一个 upsert。查看 gorm 正在运行的完整查询:

    INSERT INTO "customer_contacts" ("name","email","phone","contact_type_id","client_customer_id",
        "created_at","updated_at","doppl_client_id","id") 
    VALUES ('Jessica2','blah@blah.com','555555555',1,'a375380a-0450-4670-8e23-9dc1d08249cd',
        '2021-01-26 18:12:05.744','2021-01-26 18:12:05.744','d97a96ca-6b05-423a-814c-7c4ba2a5ebe4',
        'd749018f-5484-4308-a60d-3ef86a896a6b')
    ON CONFLICT ("id") DO UPDATE SET "client_customer_id"="excluded"."client_customer_id" 
    RETURNING "id"
    

    (这必须是不带FullSaveAssociation: trueUpdates 调用的查询)

    它有一个 ON CONFLICT 子句,因此当主键已经存在时,而不是插入它来更新 customer_contact 记录的 client_customer_id。您会发现FullSaveAssociation: true 会更改为更新所有字段。

    【讨论】:

    • 是的,但是,永远不会有冲突,因为我有一个钩子,它将为每个插入创建一个 id。 func (base *Base) BeforeCreate(tx *gorm.DB) error { base.ID = base.createUuid() t := base.createUTCTime() base.CreatedAt = t base.UpdatedAt = t return nil }
    • 如果我没有那个钩子,GORM 似乎不会为每个模型创建 id。我显然不明白。
    • 您已经指出 postgresql 将是生成带有标签 default:uuid_generate_v4(); 的新 ID 的人。这不工作吗?如果你总是生成一个新的 ID,你肯定会遇到这类问题,因为这是 gorm 用来判断一个实体是否是新的。然而,更新 AFAIK 不应导致 BeforeCreate 被调用。
    • 默认值:uuid_generate_v4() 在我的情况下似乎不起作用。
    【解决方案2】:

    我猜是 GORM 的工作方式,如果我检查我的模型当前是否有一个 id,那么我就不会创建一个新的 id。这种方法似乎行得通。

    【讨论】:

      猜你喜欢
      • 2014-05-21
      • 1970-01-01
      • 2016-12-25
      • 2020-09-24
      • 1970-01-01
      • 2022-01-07
      • 1970-01-01
      • 1970-01-01
      • 2021-03-17
      相关资源
      最近更新 更多