0

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?

1 Answer 1

0

Forgive me, but I strongly advise to read the manual.

Gorm in general

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

Your example

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

Sign up to request clarification or add additional context in comments.

4 Comments

I was using the struct way like you illustrated in the answer but I tried to use the map way just for practice because it's mentioned in the docs in this link gorm.io/docs/create.html#Create-From-Map
@AmgadDeyaa well, it also says "NOTE When creating from map, hooks won’t be invoked, associations won’t be saved and primary key values won’t be back filled". This "feature" is condemnable, exactly for the reasons Robert Pike mentioned.
Thank you for illustrating it to me this is the first time I study from docs ( I am a beginner ) so it's a little bit challenging. Thank you.
@AmgadDeyaa You are very welcome.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.