Problem
GORM is a great Golang Object Relation Mapper and saved us tons of time when developing CyberSift products. However, there were instances when using the FirstOrCreate function where a new record was simply not created
Troubleshooting
After creating a simple toy Golang program (shown below) we actually see that the new record IS created, but it’s empty

import (
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type Product struct {
gorm.Model
Code string
Price uint
}
func Main() {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
// Migrate the schema
db.AutoMigrate(&Product{})
// ❌ Will *NOT* create properly - string conditions in WHERE
db.Model(&Product{}).Where("code = ? AND price = ?", "WhereStringConditions", 200).FirstOrCreate(&Product{})
// ✅ Will create - struct conditions in WHERE
db.Model(&Product{}).Where(&Product{Code: "WhereStructConditions", Price: 250}).FirstOrCreate(&Product{})
// ✅ Will create - struct conditions in FirstOrCreate
db.Model(&Product{}).FirstOrCreate(&Product{}, &Product{Code: "FirstOrCreateStructConditions", Price: 350})
}
Solution
It turns out that GORM ignores any conditions expressed as a string and ONLY support WHERE/FirstOrCreate conditions that are expressed as structs. To be fair, this is mentioned indirectly in the documentation.
So as per the comments in the code above, the solution is to avoid using string “where” conditions, and instead rely on structs. However, be aware that in certain (typically infrequent) cases this may be tricky to adhere to when you have a complex query that relies on SQL functions like JOIN, etc…

You must be logged in to post a comment.