教程 > gorm 教程 > 阅读:188

gorm 创建——迹忆客-ag捕鱼王app官网

创建记录

user := user{name: "jinzhu", age: 18, birthday: time.now()}
result := db.create(&user) // 通过数据的指针来创建
user.id             // 返回插入数据的主键
result.error        // 返回 error
result.rowsaffected // 返回插入记录的条数

用指定的字段创建记录

创建记录并更新给出的字段。

db.select("name", "age", "createdat").create(&user)
// insert into `users` (`name`,`age`,`created_at`) values ("jinzhu", 18, "2020-07-04 11:05:21.775")

创建一个记录且一同忽略传递给略去的字段值。

db.omit("name", "age", "createdat").create(&user)
// insert into `users` (`birthday`,`updated_at`) values ("2020-01-01 00:00:00.000", "2020-07-04 11:05:21.775")

批量插入

要有效地插入大量记录,请将一个 slice 传递给 create 方法。 gorm 将生成单独一条sql语句来插入所有数据,并回填主键的值,钩子方法也会被调用。

var users = []user{{name: "jinzhu1"}, {name: "jinzhu2"}, {name: "jinzhu3"}}
db.create(&users)
for _, user := range users {
  user.id // 1,2,3
}

使用 createinbatches 分批创建时,你可以指定每批的数量,例如:

var users = []user{{name: "jinzhu_1"}, ...., {name: "jinzhu_10000"}}
// 数量为 100
db.createinbatches(users, 100)

upsert 和 create with associations 也支持批量插入

注意 使用createbatchsize 选项初始化 gorm 时,所有的创建& 关联 insert 都将遵循该选项

db, err := gorm.open(sqlite.open("gorm.db"), &gorm.config{
  createbatchsize: 1000,
})
db := db.session(&gorm.session{createbatchsize: 1000})
users = [5000]user{{name: "jinzhu", pets: []pet{pet1, pet2, pet3}}...}
db.create(&users)
// insert into users xxx (5 batches)
// insert into pets xxx (15 batches)

创建钩子

gorm 允许用户定义的钩子有 beforesave, beforecreate, aftersave, aftercreate 创建记录时将调用这些钩子方法,请参考 hooks 中关于生命周期的详细信息

func (u *user) beforecreate(tx *gorm.db) (err error) {
  u.uuid = uuid.new()
    if u.role == "admin" {
        return errors.new("invalid role")
    }
    return
}

如果想跳过 钩子 方法,可以使用 skiphooks 会话模式,例如:

db.session(&gorm.session{skiphooks: true}).create(&user)
db.session(&gorm.session{skiphooks: true}).create(&users)
db.session(&gorm.session{skiphooks: true}).createinbatches(users, 100)

根据 map 创建

gorm 支持根据 map[string]interface{}[]map[string]interface{}{} 创建记录,例如:

db.model(&user{}).create(map[string]interface{}{
  "name": "jinzhu", "age": 18,
})
// batch insert from `[]map[string]interface{}{}`
db.model(&user{}).create([]map[string]interface{}{
  {"name": "jinzhu_1", "age": 18},
  {"name": "jinzhu_2", "age": 20},
})

注意 : 根据 map 创建记录时,association 不会被调用,且主键也不会自动填充


使用 sql 表达式、context valuer 创建记录

gorm 允许使用 sql 表达式插入数据,有两种方法实现这个目标。根据 map[string]interface{} 或 自定义数据类型 创建,例如:

// 通过 map 创建记录
db.model(user{}).create(map[string]interface{}{
  "name": "jinzhu",
  "location": clause.expr{sql: "st_pointfromtext(?)", vars: []interface{}{"point(100 100)"}},
})
// insert into `users` (`name`,`location`) values ("jinzhu",st_pointfromtext("point(100 100)"));
// 通过自定义类型创建记录
type location struct {
    x, y int
}
// scan 方法实现了 sql.scanner 接口
func (loc *location) scan(v interface{}) error {
  // scan a value into struct from database driver
}
func (loc location) gormdatatype() string {
  return "geometry"
}
func (loc location) gormvalue(ctx context.context, db *gorm.db) clause.expr {
  return clause.expr{
    sql:  "st_pointfromtext(?)",
    vars: []interface{}{fmt.sprintf("point(%d %d)", loc.x, loc.y)},
  }
}
type user struct {
  name     string
  location location
}
db.create(&user{
  name:     "jinzhu",
  location: location{x: 100, y: 100},
})
// insert into `users` (`name`,`location`) values ("jinzhu",st_pointfromtext("point(100 100)"))

高级选项

关联创建

创建关联数据时,如果关联值是非零值,这些关联会被 upsert,且它们的 hook 方法也会被调用

type creditcard struct {
  gorm.model
  number   string
  userid   uint
}
type user struct {
  gorm.model
  name       string
  creditcard creditcard
}
db.create(&user{
  name: "jinzhu",
  creditcard: creditcard{number: "411111111111"}
})
// insert into `users` ...
// insert into `credit_cards` ...

我们也可以通过 select、 omit 跳过关联保存,例如:

db.omit("creditcard").create(&user)
// 跳过所有关联
db.omit(clause.associations).create(&user)

默认值

我们可以通过标签 default 为字段定义默认值,如:

type user struct {
  id   int64
  name string `gorm:"default:galeone"`
  age  int64  `gorm:"default:18"`
}

插入记录到数据库时,默认值 会被用于 填充值为 零值 的字段

注意 对于声明了默认值的字段,像 0、''、false 等零值是不会保存到数据库。您需要使用指针类型或 scanner/valuer 来避免这个问题,例如:

type user struct {
  gorm.model
  name string
  age  *int           `gorm:"default:18"`
  active sql.nullbool `gorm:"default:true"`
}

注意 若要数据库有默认、虚拟/生成的值,你必须为字段设置 default 标签。若要在迁移时跳过默认值定义,你可以使用 default:(-),例如:

type user struct {
  id        string `gorm:"default:uuid_generate_v3()"` // db func
  firstname string
  lastname  string
  age       uint8
  fullname  string `gorm:"->;type:generated always as (concat(firstname,' ',lastname));default:(-);"`
}

使用虚拟/生成的值时,你可能需要禁用它的创建、更新权限,查看 字段级权限 获取详情


upsert 及冲突

gorm 为不同数据库提供了兼容的 upsert 支持

import "gorm.io/gorm/clause"
// do nothing on conflict
db.clauses(clause.onconflict{donothing: true}).create(&user)
// update columns to default value on `id` conflict
db.clauses(clause.onconflict{
  columns:   []clause.column{{name: "id"}},
  doupdates: clause.assignments(map[string]interface{}{"role": "user"}),
}).create(&users)
// merge into "users" using *** when not matched then insert *** when matched then update set ***; sql server
// insert into `users` *** on duplicate key update ***; mysql
// use sql expression
db.clauses(clause.onconflict{
  columns:   []clause.column{{name: "id"}},
  doupdates: clause.assignments(map[string]interface{}{"count": gorm.expr("greatest(count, values(count))")}),
}).create(&users)
// insert into `users` *** on duplicate key update `count`=greatest(count, values(count));
// update columns to new value on `id` conflict
db.clauses(clause.onconflict{
  columns:   []clause.column{{name: "id"}},
  doupdates: clause.assignmentcolumns([]string{"name", "age"}),
}).create(&users)
// merge into "users" using *** when not matched then insert *** when matched then update set "name"="excluded"."name"; sql server
// insert into "users" *** on conflict ("id") do update set "name"="excluded"."name", "age"="excluded"."age"; postgresql
// insert into `users` *** on duplicate key update `name`=values(name),`age`=values(age); mysql
// update all columns to new value on conflict except primary keys and those columns having default values from sql func
db.clauses(clause.onconflict{
  updateall: true,
}).create(&users)
// insert into "users" *** on conflict ("id") do update set "name"="excluded"."name", "age"="excluded"."age", ...;
// insert into `users` *** on duplicate key update `name`=values(name),`age`=values(age), ...; mysql

我们还可以查看 高级查询 中的 firstorinitfirstorcreate

查看 原生 sql 及构造器 获取更多细节

查看笔记

扫码一下
查看教程更方便
网站地图