创建记录
user := User{Name: " Jinzhu " , Age: 18 , Birthday: time.Now()}
result := db.Create(&user) // 将数据指针传递给 Create
user.ID // 返回插入数据的主键
result.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")
创建记录并忽略传递给 omit 的字段值。
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")
批量插入
要有效地插入大量记录,请将切片传递给该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 )
注意使用
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 。这些钩子方法将在创建记录时调用,有关生命周期的详细信息,请参阅
钩子
?
func (u *User) BeforeCreate (tx *gorm.DB) (err error) {
u.UUID = uuid.New()
if u.Role == "admin" { return errors.New( "invalid role" ) } return }
如果要跳过Hooks 方法,可以使用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 )
从地图创建
GORM 支持从
map[string]interface{} 和创建
[]map[string]interface{}{} ,例如:
db.Model(&User{}).Create( map [ string ] interface {}{ "Name" : "jinzhu" , "Age" : 18 , })
// 从 `[]map[string]interface{}{}`
db.Model(&User{}).Create([] map [ string ] interface {}{
{ "Name" : "jinzhu_1" , "Age" : 18 },
{ "姓名" : "jinzhu_2" , "Age" : 20 },
})
从 SQL 表达式/上下文赋值器创建
// 从地图创建
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 interface
func (loc *Location) Scan (v interface {}) error { // 从数据库驱动程序扫描一个值到 struct }
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 (“点(100 100)”))
先进的
用关联创建
当创建一些带有关联的数据时,如果它的关联值不是零值,这些关联将被更新,并且它的Hooks 方法将被调用。
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
type User struct {
gorm.Model
Name string
CreditCard CreditCard
}
db.Create(用户{
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)
默认值
您可以为带有 tag 的字段定义默认值default ,例如:
type User struct {
ID int64
Name string `gorm:"default:galeone"`
Age int64 `gorm:"default:18"`
}
注意任何像0 ,?'' ,一样的零值false 都不会被保存到那些定义了默认值的字段的数据库中,您可能希望使用指针类型或扫描器/值器来避免这种情况,例如:
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 ));默认值:(-);"`
}
使用虚拟/生成值时,您可能需要禁用其创建/更新权限,请查看字段级权限
GORM 为不同的数据库提供兼容的 Upsert 支持
导入 “gorm.io/gorm/clause”
// 对冲突不做任何处理
db.Clauses(clause.OnConflict{DoNothing: true }).Create(&user)
// 在 `id` 冲突时将列更新为默认值
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
// 使用 SQL 表达式
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) );
// 在 `id` 冲突时将列更新为新值
db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id" }},
DoUpdates: clause.AssignmentColumns([] string { "name" , "age" }),
}).Create(&users)
// 合并到 "users" 使用 *** 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), `年龄=值(年龄); MySQL
// 将除主键之外的所有列更新为冲突时的新值
db.Clauses(clause.OnConflict{
UpdateAll: true ,
}).Create(&users)
// INSERT INTO "users" *** ON CONFLICT ("id" ) DO UPDATE SET "name"="excluded"."name", "age"="excluded"."age", ...;
|