【问题标题】:A complex update in GORMGORM 中的复杂更新
【发布时间】:2020-06-05 17:00:52
【问题描述】:

我在 GORM 中有一个以 Postgres 作为数据库的模型。模型是这样的

type Country struct {
    gorm.Model
    Name   string
    Population int64
    Regions []Region
}

type Region struct {
    gorm.Model
    Name   string
    Cities []City
    CountryID uint `sql:"type:bigint REFERENCES countries(id) ON DELETE CASCADE" json:"-"`
}

type City struct {
    gorm.Model
    Name        string
    Comment string
    RegionID   uint `sql:"type:bigint REFERENCES regions(id) ON DELETE CASCADE" json:"-"`
}

当我从模型创建新记录时,我调用创建函数

db.Create(&menu)

现在,我正在尝试更新模型,但遇到了一些问题。 如果我调用这个

err = db.Debug().Where("id = ?", countryId).Updates(&country).Error

我有一个错误,模型没有在数据库中更新 更新: 错误是


(C:/source/go/gorm/country.go:100) 
[2020-06-06 02:37:59]  sql: converting argument $4 type: unsupported type []main.Region, a slice of struct 

(C:/source/go/gorm/country.go:100) 
[2020-06-06 02:37:59]  [0.00ms]  UPDATE "" SET "created_at" = '2020-06-06 00:37:50', "id" = 1, "name" = 'New Name', "regions" = '[{{1 2020-06-06 00:37:50.450497 +0000 UTC 2020-06-06 00:37:50.450497 +0000 UTC <nil>} Region 1 [{{1 2020-06-06 00:37:50.465029 +0000 UTC 2020-06-06 00:37:50.465029 +0000 UTC <nil>} City 1  1}] 1} {{0 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC <nil>} Region 2 updated [{{0 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC <nil>} City 2 updated  0}] 0}]', "updated_at" = '2020-06-06 00:37:50'  WHERE (id = 1)  
[0 rows affected or returned ] 

如果我跑了

err = db.Debug().Model(&country).Association("Regions").Replace(country.Regions).Error

地区和城市模型在数据库中更新,但国家模型未更新。 此外,对于区域模型,在更新删除元素时 CountryID 为 null,但城市模型不会更新其 RegionID 以取消引用。

如何更新这样的完整模型?

更新:

我不知道如何更新完整的 Country 模型。 这是执行的完整查询。

Create Tables

(C:/source/go/gorm/country.go:35) 
[2020-06-06 01:33:29]  [36;1m[20.02ms]  CREATE TABLE "countries" ("id" serial,"created_at" timestamp with time zone,"updated_at" timestamp with time zone,"deleted_at" timestamp with time zone,"name" text,"population" bigint , PRIMARY KEY ("id"))  
[36;31m[0 rows affected or returned ]

(C:/source/go/gorm/country.go:35) 
[2020-06-06 01:33:29]  [36;1m[16.00ms]  CREATE INDEX idx_countries_deleted_at ON "countries"(deleted_at)   
[36;31m[0 rows affected or returned ]

(C:/source/go/gorm/country.go:36) 
[2020-06-06 01:33:29]  [36;1m[28.99ms]  CREATE TABLE "regions" ("id" serial,"created_at" timestamp with time zone,"updated_at" timestamp with time zone,"deleted_at" timestamp with time zone,"name" text,"country_id" bigint REFERENCES countries(id) ON DELETE CASCADE , PRIMARY KEY ("id"))  
[36;31m[0 rows affected or returned ]

(C:/source/go/gorm/country.go:36) 
[2020-06-06 01:33:29]  [36;1m[11.99ms]  CREATE INDEX idx_regions_deleted_at ON "regions"(deleted_at)   
[36;31m[0 rows affected or returned ]

(C:/source/go/gorm/country.go:37) 
[2020-06-06 01:33:29]  [36;1m[18.99ms]  CREATE TABLE "cities" ("id" serial,"created_at" timestamp with time zone,"updated_at" timestamp with time zone,"deleted_at" timestamp with time zone,"name" text,"comment" text,"region_id" bigint REFERENCES regions(id) ON DELETE CASCADE , PRIMARY KEY ("id"))  
[36;31m[0 rows affected or returned ]

(C:/source/go/gorm/country.go:37) 
[2020-06-06 01:33:29]  [36;1m[32.00ms]  CREATE INDEX idx_cities_deleted_at ON "cities"(deleted_at)   
[36;31m[0 rows affected or returned ] 
Add Country Model

(C:/source/go/gorm/country.go:64) 
[2020-06-06 01:33:32]  [36;1m[3.99ms]  INSERT INTO "countries" ("created_at","updated_at","deleted_at","name","population") VALUES ('2020-06-06 01:33:32','2020-06-06 01:33:32',NULL,'Country 1',0) RETURNING "countries"."id"  
[36;31m[1 rows affected or returned ]

(C:/source/go/gorm/country.go:64) 
[2020-06-06 01:33:32]  [36;1m[4.00ms]  INSERT INTO "regions" ("created_at","updated_at","deleted_at","name","country_id") VALUES ('2020-06-06 01:33:32','2020-06-06 01:33:32',NULL,'Region 1',1) RETURNING "regions"."id"  
[36;31m[1 rows affected or returned ]

(C:/source/go/gorm/country.go:64) 
[2020-06-06 01:33:32]  [36;1m[3.00ms]  INSERT INTO "cities" ("created_at","updated_at","deleted_at","name","comment","region_id") VALUES ('2020-06-06 01:33:32','2020-06-06 01:33:32',NULL,'City 1','',1) RETURNING "cities"."id"  
[36;31m[1 rows affected or returned ]

(C:/source/go/gorm/country.go:64) 
[2020-06-06 01:33:32]  [36;1m[4.00ms]  INSERT INTO "regions" ("created_at","updated_at","deleted_at","name","country_id") VALUES ('2020-06-06 01:33:32','2020-06-06 01:33:32',NULL,'Region 2',1) RETURNING "regions"."id"  
[36;31m[1 rows affected or returned ]

(C:/source/go/gorm/country.go:64) 
[2020-06-06 01:33:32]  [36;1m[3.83ms]  INSERT INTO "cities" ("created_at","updated_at","deleted_at","name","comment","region_id") VALUES ('2020-06-06 01:33:32','2020-06-06 01:33:32',NULL,'City 2','',2) RETURNING "cities"."id"  
[36;31m[1 rows affected or returned ]
Update Country Model

(C:/source/go/gorm/country.go:75) 
[2020-06-06 01:33:39]  [36;1m[3.99ms]  SELECT * FROM "countries"  WHERE "countries"."deleted_at" IS NULL AND ((id = 1))  
[36;31m[1 rows affected or returned ]

(C:/source/go/gorm/country.go:75) 
[2020-06-06 01:33:39]  [36;1m[4.00ms]  SELECT * FROM "regions"  WHERE "regions"."deleted_at" IS NULL AND (("country_id" IN (1)))  
[36;31m[2 rows affected or returned ]

(C:/source/go/gorm/country.go:75) 
[2020-06-06 01:33:39]  [36;1m[3.00ms]  SELECT * FROM "cities"  WHERE "cities"."deleted_at" IS NULL AND (("region_id" IN (1,2)))  
[36;31m[2 rows affected or returned ]
{{1 2020-06-05 23:33:32.660156 +0000 UTC 2020-06-05 23:33:32.660156 +0000 UTC <nil>} Country 1 0 [{{1 2020-06-05 23:33:32.664151 +0000 UTC 2020-06-05 23:33:32.664151 +0000 UTC <nil>} Region 1 [{{1 2020-06-05 23:33:32.668156 +0000 UTC 2020-06-05 23:33:32.668156 +0000 UTC <nil>} City 1  1}] 1} {{2 2020-06-05 23:33:32.672155 +0000 UTC 2020-06-05 23:33:32.672155 +0000 UTC <nil>} Region 2 [{{2 2020-06-05 23:33:32.676156 +0000 UTC 2020-06-05 23:33:32.676156 +0000 UTC <nil>} City 2  2}] 1}]}

(C:/source/go/gorm/country.go:99) 
[2020-06-06 01:33:39]  [36;1m[3.00ms]  UPDATE "regions" SET "created_at" = '2020-06-05 23:33:32', "updated_at" = '2020-06-06 01:33:39', "deleted_at" = NULL, "name" = 'Region 1', "country_id" = 1  WHERE "regions"."deleted_at" IS NULL AND "regions"."id" = 1  
[36;31m[1 rows affected or returned ]

() 
[2020-06-06 01:33:39]  [36;1m[6.00ms]  UPDATE "cities" SET "created_at" = '2020-06-05 23:33:32', "updated_at" = '2020-06-06 01:33:39', "deleted_at" = NULL, "name" = 'City 1', "comment" = '', "region_id" = 1  WHERE "cities"."deleted_at" IS NULL AND "cities"."id" = 1  
[36;31m[1 rows affected or returned ]

(C:/source/go/gorm/country.go:99) 
[2020-06-06 01:33:39]  [36;1m[4.00ms]  SELECT * FROM "countries"  WHERE "countries"."deleted_at" IS NULL AND "countries"."id" = 1 ORDER BY "countries"."id" ASC LIMIT 1  
[36;31m[1 rows affected or returned ]

(C:/source/go/gorm/country.go:99) 
[2020-06-06 01:33:39]  [36;1m[3.00ms]  UPDATE "regions" SET "created_at" = '2020-06-05 23:33:32', "updated_at" = '2020-06-06 01:33:39', "deleted_at" = NULL, "name" = 'Region 1', "country_id" = 1  WHERE "regions"."deleted_at" IS NULL AND "regions"."id" = 1  
[36;31m[1 rows affected or returned ]

() 
[2020-06-06 01:33:39]  [36;1m[4.99ms]  UPDATE "cities" SET "created_at" = '2020-06-05 23:33:32', "updated_at" = '2020-06-06 01:33:39', "deleted_at" = NULL, "name" = 'City 1', "comment" = '', "region_id" = 1  WHERE "cities"."deleted_at" IS NULL AND "cities"."id" = 1  
[36;31m[1 rows affected or returned ]

(C:/source/go/gorm/country.go:99) 
[2020-06-06 01:33:39]  [36;1m[4.00ms]  INSERT INTO "regions" ("created_at","updated_at","deleted_at","name","country_id") VALUES ('2020-06-06 01:33:39','2020-06-06 01:33:39',NULL,'Region 2 updated',1) RETURNING "regions"."id"  
[36;31m[1 rows affected or returned ]

() 
[2020-06-06 01:33:39]  [36;1m[3.99ms]  INSERT INTO "cities" ("created_at","updated_at","deleted_at","name","comment","region_id") VALUES ('2020-06-06 01:33:39','2020-06-06 01:33:39',NULL,'City 2 updated','',3) RETURNING "cities"."id"  
[36;31m[1 rows affected or returned ]

(C:/source/go/gorm/country.go:99) 
[2020-06-06 01:33:39]  [36;1m[3.00ms]  SELECT * FROM "countries"  WHERE "countries"."deleted_at" IS NULL AND "countries"."id" = 1 ORDER BY "countries"."id" ASC LIMIT 1  
[36;31m[1 rows affected or returned ]

(C:/source/go/gorm/country.go:99) 
[2020-06-06 01:33:39]  [36;1m[3.99ms]  UPDATE "regions" SET "country_id" = NULL  WHERE "regions"."deleted_at" IS NULL AND (("id" NOT IN (1,3)) AND ("country_id" = 1))  
[36;31m[1 rows affected or returned ]


【问题讨论】:

  • 请添加您收到的错误并从控制台执行查询
  • @Eklavya 问题随着查询的执行而更新

标签: database go orm go-gorm


【解决方案1】:

要更新现有数据,您可以获取第一个预加载子项

var country Country
db.Preload("Regions").Preload("Regions.Cities").First(&country, 1)

然后您可以更新数据并添加新数据,例如

country.Regions[0].Cities[0].Name = "Dhaka City 1"
country.Regions[0].Name = "Dhaka Region 1"
country.Regions[1].Cities = append(country.Regions[1].Cities, City{Name: "Dhaka City 2"})

现在将更新的数据保存到数据库中

db.Save(&country)

如果您只想添加新的子数据,您也可以避免 Preload。

db.First(&country, 8)
country.Regions = append(country.Regions, Region{Name: "Dhaka Region 3"})
db.Save(&country)

默认gormassociation_autoupdate标志设置为true,所以是自动保存关联。

err = db.Debug().Model(&country).Association("Regions").Replace(country.Regions).Error

Replace 仅用其他方式替换关联方式。如果您不提供任何信息,它只会在此处删除与 Country 的当前关联。而且只有Regions 不是儿童城市。

Gorm 不支持更新时的任何删除操作。它仅用于添加或更新现有数据。 Gorm 模型默认使用软删除。如果您以这种方式删除 Regions,它将更新 deleted_at 字段数据。并且在查询时它总是过滤掉已删除的数据。

db.Delete(county.Regions)

而且它不会软删除 City,你必须这样做。

db.Delete(region.Cities)

一个工作代码示例here

【讨论】:

  • County = Country 有错别字
  • 我在这里添加了一些解释
  • 谢谢@Eklavya。根据您的示例,我创建了这个play.golang.com/p/lzR5h_pq7gU。如您所见,当我运行 UpdateRemoveOneCityFromLastRegion 函数时,没有从 Cities 中删除任何内容
  • @J19 是的,更新不会删除数据,我已经解释过了
  • 感谢@Eklavya。我认为 gorm 与其他平台(如 dot net 上的 java)中的 orm 相比,是一个玩具 orm。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多