如何使用GORM创建或更新记录?
Gorm有一个如何使用GORM创建或更新记录?,go,orm,go-gorm,Go,Orm,Go Gorm,Gorm有一个FirstOrCreate方法和一个FirstOrInit,但是之后如何检查记录是否确实创建了?我喜欢创建一个不存在的记录,如果它存在,我想更新一些字段。下面是gorm文档中的示例 见ATTR。它不会确切地告诉您是否确实创建了记录,但只允许您在记录确实创建时更新某些字段(这似乎是您最终想要实现的) 如果存在,那么 UPDATE "aggregated_data" SET "data" = '[{"a":2}]', "type" = '2' WHERE "aggregated_d
FirstOrCreate
方法和一个FirstOrInit
,但是之后如何检查记录是否确实创建了?我喜欢创建一个不存在的记录,如果它存在,我想更新一些字段。下面是gorm文档中的示例
见ATTR。它不会确切地告诉您是否确实创建了记录,但只允许您在记录确实创建时更新某些字段(这似乎是您最终想要实现的)
如果存在,那么
UPDATE "aggregated_data" SET "data" = '[{"a":2}]', "type" = '2' WHERE "aggregated_data"."id" = '2' AND (("aggregated_data"."type" = '2'))
否则
更新2020.10.09
谢谢你
从1.20.x开始,GORM为不同的数据库提供兼容的Upsert支持()
//将列更新为'id'上的新值冲突
DB.条款{
列:[]子句。列{{Name:“id”},//键列
doUpdate:clause.AssignmentColumns([]字符串{“name”,“age”}),//需要更新列
}).创建(&用户)
//在不匹配时使用***合并到“用户”,然后在匹配时插入***,然后更新集“名称”=“排除”。“名称”;SQL Server
//在“用户”***中插入冲突(“id”)是否更新设置“名称”=“已排除”。“名称”,“年龄”=“已排除”。“年龄”;PostgreSQL
//在重复密钥更新时将`name`=值(名称),`age=值(年龄)插入`users`***;MySQL
对于gorm 1.9.x或更低版本,首先更新,然后在不存在时插入更有效
// update only set name=nick
if err := db.Model(&newUser).Where("id = ?", 3333).Update("name", "nick").Error; err != nil {
// always handle error like this, cause errors maybe happened when connection failed or something.
// record not found...
if gorm.IsRecordNotFoundError(err){
db.Create(&newUser) // create new record from newUser
}
}
FirstOrInit
和FirstOrCreate
是不同的。如果数据库中没有匹配记录,FirstOrInit
将初始化结构,但不创建记录,FirstOrCreate
将创建一条记录,并向结构查询该记录。投票最多的答案对我不起作用,但这确实:
user := NewUser(email, password)
if db.Model(&user).Where("email = ?", email).Updates(&user).RowsAffected == 0 {
db.Create(&user)
}
这适用于gorm v1.9.15和go 1.13,有更好的方法:
func CreateOrUpdate(db *gorm.DB, model interface{}, where interface{}, update interface{}) (interface{}, error) {
var result interface{}
err := db.Model(model).Where(where).First(result).Error
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, err
} else {
//insert
if err = db.Model(model).Create(update).Error; err != nil {
return nil, err
}
}
}
//not update some field
reflect.ValueOf(update).Elem().FieldByName("someField").SetInt(0)
if err = db.Model(model).Where(where).Updates(update).Error; err != nil {
return nil, err
}
return update, nil
}
if err := db.Where(User{Email: "some@email.com"}).
Assign(User{Email: "some@email.com", Age: 45}).
FirstOrCreate(&User{}).Error; err != nil {
c.Next(err)
return
}
在本例中,如果用户使用电子邮件“some@email.com,则“年龄”字段将被更新。相反,如果找不到用户,则创建它
请注意,我将丢弃创建的用户,但如果需要,您可以保留引用。
此外,出于某些GORM原因,要求在Assign子句中至少提供一个筛选器字段,这就是为什么您会看到电子邮件被填充两次。正确的链接在这里:(无法编辑,因为它少于6个字符)将嵌入链接从curd更改为crud这对我来说没有意义-为什么需要指定where子句来更新现有记录。如果用户对象是现有记录,那么它应该已经有了id,我希望gorm足够聪明,知道如果id存在,它应该更新。我为Java编写了一个类似gorm的库,它只需要调用save(),而不管记录是否为新记录-如果记录没有id,它将插入记录,如果记录有id,它将进行更新。问题是“如果它存在,我想更新一些字段”。因此,您必须检查它是否存在,如果存在,您只能更新所选字段。如果您使用
db.save(&user)
,则用户世界中的所有字段都将写入db。Gorm现在拥有对upsert的一流支持
user := NewUser(email, password)
if db.Model(&user).Where("email = ?", email).Updates(&user).RowsAffected == 0 {
db.Create(&user)
}
func CreateOrUpdate(db *gorm.DB, model interface{}, where interface{}, update interface{}) (interface{}, error) {
var result interface{}
err := db.Model(model).Where(where).First(result).Error
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, err
} else {
//insert
if err = db.Model(model).Create(update).Error; err != nil {
return nil, err
}
}
}
//not update some field
reflect.ValueOf(update).Elem().FieldByName("someField").SetInt(0)
if err = db.Model(model).Where(where).Updates(update).Error; err != nil {
return nil, err
}
return update, nil
}
if err := db.Where(User{Email: "some@email.com"}).
Assign(User{Email: "some@email.com", Age: 45}).
FirstOrCreate(&User{}).Error; err != nil {
c.Next(err)
return
}