Create
Create Record
Generics API
user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
ctx := context.Background()
err := gorm.G[User](db).Create(ctx, &user)
result := gorm.WithResult()
err := gorm.G[User](db, result).Create(ctx, &user)
user.ID
result.Error
result.RowsAffected Traditional API
user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
result := db.Create(&user)
user.ID
result.Error
result.RowsAffected We can also create multiple records with Create():
users := []*User{
{Name: "Jinzhu", Age: 18, Birthday: time.Now()},
{Name: "Jackson", Age: 19, Birthday: time.Now()},
}
result := db.Create(users)
result.Error
result.RowsAffected NOTE You cannot pass a struct to ‘create’, so you should pass a pointer to the data.
Create Record With Selected Fields
Create a record and assign a value to the fields specified.
db.Select("Name", "Age", "CreatedAt").Create(&user)
Create a record and ignore the values for fields passed to omit.
db.Omit("Name", "Age", "CreatedAt").Create(&user)
Batch Insert
To efficiently insert large number of records, pass a slice to the Create method. GORM will generate a single SQL statement to insert all the data and backfill primary key values, hook methods will be invoked too. It will begin a transaction when records can be split into multiple batches.
var users = []User{{Name: "jinzhu1"}, {Name: "jinzhu2"}, {Name: "jinzhu3"}}
db.Create(&users)
for _, user := range users {
user.ID
}You can specify batch size when creating with CreateInBatches, e.g:
var users = []User{{Name: "jinzhu_1"}, ...., {Name: "jinzhu_10000"}}
db.CreateInBatches(users, 100)Batch Insert is also supported when using Upsert and Create With Associations
NOTE initialize GORM with
CreateBatchSizeoption, allINSERTwill respect this option when creating record & associations
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)
Create Hooks
GORM allows user defined hooks to be implemented for BeforeSave, BeforeCreate, AfterSave, AfterCreate. These hook method will be called when creating a record, refer Hooks for details on the lifecycle
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
u.UUID = uuid.New()
if u.Role == "admin" {
return errors.New("invalid role")
}
return
}If you want to skip Hooks methods, you can use the SkipHooks session mode, for example:
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)Create From Map
GORM supports create from map[string]interface{} and []map[string]interface{}{}, e.g:
db.Model(&User{}).Create(map[string]interface{}{
"Name": "jinzhu", "Age": 18,
})
db.Model(&User{}).Create([]map[string]interface{}{
{"Name": "jinzhu_1", "Age": 18},
{"Name": "jinzhu_2", "Age": 20},
})NOTE When creating from map, hooks won’t be invoked, associations won’t be saved and primary key values won’t be back filled
Create From SQL Expression/Context Valuer
GORM allows insert data with SQL expression, there are two ways to achieve this goal, create from map[string]interface{} or Customized Data Types, for example:
db.Model(User{}).Create(map[string]interface{}{
"Name": "jinzhu",
"Location": clause.Expr{SQL: "ST_PointFromText(?)", Vars: []interface{}{"POINT(100 100)"}},
})
type Location struct {
X, Y int
}
func (loc *Location) Scan(v interface{}) error {
}
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},
})
Advanced
Create With Associations
When creating some data with associations, if its associations value is not zero-value, those associations will be upserted, and its Hooks methods will be invoked.
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"}
})
You can skip saving associations with Select, Omit, for example:
db.Omit("CreditCard").Create(&user)
db.Omit(clause.Associations).Create(&user)Default Values
You can define default values for fields with tag default, for example:
type User struct {
ID int64
Name string `gorm:"default:galeone"`
Age int64 `gorm:"default:18"`
}Then the default value will be used when inserting into the database for zero-value fields
NOTE Any zero value like
0,'',falsewon’t be saved into the database for those fields defined default value, you might want to use pointer type or Scanner/Valuer to avoid this, for example:
type User struct {
gorm.Model
Name string
Age *int `gorm:"default:18"`
Active sql.NullBool `gorm:"default:true"`
}NOTE You have to setup the
defaulttag for fields having default or virtual/generated value in database, if you want to skip a default value definition when migrating, you could usedefault:(-), for example:
type User struct {
ID string `gorm:"default:uuid_generate_v3()"`
FirstName string
LastName string
Age uint8
FullName string `gorm:"->;type:GENERATED ALWAYS AS (concat(firstname,' ',lastname));default:(-);"`
}NOTE SQLite doesn’t support some records are default values when batch insert.
See SQLite Insert stmt. For example:type Pet struct { Name string `gorm:"default:cat"` }
db.Create(&[]Pet{{Name: "dog"}, {}})
A viable alternative is to assign default value to fields in the hook, e.g.func (p *Pet) BeforeCreate(tx *gorm.DB) (err error) {
if p.Name == "" {
p.Name = "cat"
}
}You can see more info in [issues#6335](https://github.com/go-gorm/gorm/issues/6335)
When using virtual/generated value, you might need to disable its creating/updating permission, check out Field-Level Permission
Upsert / On Conflict
GORM provides compatible Upsert support for different databases
import "gorm.io/gorm/clause"
db.Clauses(clause.OnConflict{DoNothing: true}).Create(&user)
db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
DoUpdates: clause.Assignments(map[string]interface{}{"role": "user"}),
}).Create(&users)
db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
DoUpdates: clause.Assignments(map[string]interface{}{"count": gorm.Expr("GREATEST(count, VALUES(count))")}),
}).Create(&users)
db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
DoUpdates: clause.AssignmentColumns([]string{"name", "age"}),
}).Create(&users)
db.Clauses(clause.OnConflict{
UpdateAll: true,
}).Create(&users)
Also checkout FirstOrInit, FirstOrCreate on Advanced Query
Checkout Raw SQL and SQL Builder for more details
评论
登录后参与评论
InfoSphere