title: 创建

layout: page

创建记录

  1. user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
  2. result := db.Create(&user) // 通过数据的指针来创建
  3. user.ID // 返回插入数据的主键
  4. result.Error // 返回 error
  5. result.RowsAffected // 返回插入记录的条数

选定字段创建

用选定字段的来创建

  1. db.Select("Name", "Age", "CreatedAt").Create(&user)
  2. // INSERT INTO `users` (`name`,`age`,`created_at`) VALUES ("jinzhu", 18, "2020-07-04 11:05:21.775")

创建时排除选定字段

  1. db.Omit("Name", "Age", "CreatedAt").Create(&user)
  2. // INSERT INTO `users` (`birthday`,`updated_at`) VALUES ("2020-01-01 00:00:00.000", "2020-07-04 11:05:21.775")

创建钩子

GORM 允许 BeforeSave, BeforeCreate, AfterSave, AfterCreate 等钩子,创建记录时会调用这些方法, 详情请参阅 钩子

  1. func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
  2. u.UUID = uuid.New()
  3. if u.Role == "admin" {
  4. return errors.New("invalid role")
  5. }
  6. return
  7. }

批量插入

将切片数据传递给 Create 方法,GORM 将生成一个单一的 SQL 语句来插入所有数据,并回填主键的值,钩子方法也会被调用。

  1. var users = []User{{Name: "jinzhu1"}, {Name: "jinzhu2"}, {Name: "jinzhu3"}}
  2. DB.Create(&users)
  3. for _, user := range users {
  4. user.ID // 1,2,3
  5. }

Upsert关联创建 同样支持批量插入

高级

关联创建

如果您的模型定义了任何关系(relation),并且它有非零关系,那么在创建时这些数据也会被保存

  1. type CreditCard struct {
  2. gorm.Model
  3. Number string
  4. UserID uint
  5. }
  6. type User struct {
  7. gorm.Model
  8. Name string
  9. CreditCard CreditCard
  10. }
  11. db.Create(&User{
  12. Name: "jinzhu",
  13. CreditCard: CreditCard{Number: "411111111111"}
  14. })
  15. // INSERT INTO `users` ...
  16. // INSERT INTO `credit_cards` ...

您也可以通过 SelectOmit 跳过关联保存

  1. db.Omit("CreditCard").Create(&user)
  2. // 跳过所有关联
  3. db.Omit(clause.Associations).Create(&user)

默认值

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

  1. type User struct {
  2. ID int64
  3. Name string `gorm:"default:'galeone'"`
  4. Age int64 `gorm:"default:18"`
  5. uuid.UUID UUID `gorm:"type:uuid;default:gen_random_uuid()"` // db 函数
  6. }

插入记录到数据库时,零值 字段将使用默认值

注意0''false 等零值,不会将这些字段定义的默认值保存到数据库。您需要使用指针类型或 Scanner/Valuer 来避免这个问题,例如:

  1. type User struct {
  2. gorm.Model
  3. Name string
  4. Age *int `gorm:"default:18"`
  5. Active sql.NullBool `gorm:"default:true"`
  6. }

注意 对于在数据库中有默认值的字段,你必须为其 struct 设置 default 标签,否则 GORM 将在创建时使用该字段的零值,例如:

  1. type User struct {
  2. ID string `gorm:"default:uuid_generate_v3()"`
  3. Name string
  4. Age uint8
  5. }

Upsert 及冲突

GORM 为不同数据库提供了兼容的 Upsert 支持

  1. import "gorm.io/gorm/clause"
  2. // 不处理冲突
  3. DB.Clauses(clause.OnConflict{DoNothing: true}).Create(&user)
  4. // `id` 冲突时,将字段值更新为默认值
  5. DB.Clauses(clause.OnConflict{
  6. Columns: []clause.Column{{Name: "id"}},
  7. DoUpdates: clause.Assignments(map[string]interface{}{"role": "user"}),
  8. }).Create(&users)
  9. // MERGE INTO "users" USING *** WHEN NOT MATCHED THEN INSERT *** WHEN MATCHED THEN UPDATE SET ***; SQL Server
  10. // INSERT INTO `users` *** ON DUPLICATE KEY UPDATE ***; MySQL
  11. // Update columns to new value on `id` conflict
  12. DB.Clauses(clause.OnConflict{
  13. Columns: []clause.Column{{Name: "id"}},
  14. DoUpdates: clause.AssignmentColumns([]string{"name", "age"}),
  15. }).Create(&users)
  16. // MERGE INTO "users" USING *** WHEN NOT MATCHED THEN INSERT *** WHEN MATCHED THEN UPDATE SET "name"="excluded"."name"; SQL Server
  17. // INSERT INTO "users" *** ON CONFLICT ("id") DO UPDATE SET "name"="excluded"."name", "age"="excluded"."age"; PostgreSQL
  18. // INSERT INTO `users` *** ON DUPLICATE KEY UPDATE `name`=VALUES(name),`age=VALUES(age); MySQL

也可以查看 高级查询 中的 FirstOrInit, FirstOrCreate

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