I’ve been learning GORM from the official docs, and I’m running into some confusion when trying to create records from a map using the Create() function.
The official documentation shows this example for creating records from a map:
// Single insert
db.Model(&User{}).Create(map[string]interface{}{
"Name": "jinzhu", "Age": 18,
})
// Batch insert
db.Model(&User{}).Create([]map[string]interface{}{
{"Name": "jinzhu_1", "Age": 18},
{"Name": "jinzhu_2", "Age": 20},
})
But here’s the thing — this works fine if there is no primary key (PK) defined for the table. However, if I define a PK field (like user_id
), I get an error. From what I understand, every table must have a primary key for normalization, so why does this method work without a PK?
Is there any valid use case for creating records from a map if the table has a PK? Does GORM handle PKs automatically in this case? Or is there something I’m missing, and it really doesn’t work with PKs?
I’m also wondering if the example in the docs is actually well-written or if it needs a correction for handling tables with primary keys. Should I be using structs instead of maps when working with tables that have a PK?
Forgive me, but I strongly advise to read the manual.
Assuming you have used composition to embed gorm.Model into User
like this:
type User struct {
gorm.Model
// your fields here
}
your effective User
looks like this
type User struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"
// your fields here
}
So yes, per default gorm handles the primary key for you, and you can even access the value of it easily, as documented for Create:
user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
result := db.Create(&user) // pass pointer of data to Create
user.ID // returns inserted data's primary key
result.Error // returns error
result.RowsAffected // returns inserted records count
It eludes me why you use a map[string]interface{}
. There is no good reason for that. Again, as per docs for the batch insert:
users := []*User{
{Name: "Jinzhu", Age: 18, Birthday: time.Now()},
{Name: "Jackson", Age: 19, Birthday: time.Now()},
}
result := db.Create(users)
which would translate to
result := db.Create([]*User{
{Name: "Jinzhu", Age: 18, Birthday: time.Now()},
{Name: "Jackson", Age: 19, Birthday: time.Now()},
})
One of the main advantages of Go is its type safety. With interface{}
, you give up on that. As per go proverbs:
interface{}
says nothing
I highly recommend going through all of them, as well as Effective Go