Five tips on how to use Gorm better

Francesco Pastore
3 min readNov 1, 2022

--

Gorm is one of the most used ORMs for the Go language. It is complete and very easy to use. But sometimes the documentation does not cover all the cases.

There are some functionalities that once known can help you to write better code and simplify your work. Let's see five tips on how to use Gorm better.

1. Use custom foreign key constraints

When you create relations between tables remember to update the constraints on the foreign keys. As default, Gorm set the mode “NO ACTION” for update and delete cases.

However, you could make your life easier by using specific modes like for example the “CASCADE” one. Every time a primary key is updated the relative foreign key will be too. Instead, if a referenced record is deleted also the rows that reference it will be deleted as well.

In PostgreSQL, the available constraints are:

  • SET NULL: set the foreign key to null
  • CASCADE: do the same action as done on the referenced row.
  • SET DEFAULT: set the foreign key to the default value (null or empty if not specified)
  • NO ACTION and RESTRICT: in few words, they do not allow some operations on the referenced row. Look to the documentation to read more details about them.
An example of specific constraints defined on the model.

2. Not using debug when stuck

One of the easiest ways to find errors is to use the inner debug utility available with Gorm. You just need to prepend “. Debug()” to your function call and you are done! Now, all the queries will be executed as before but in addition, the statement is printed.

db.Debug().
Table("users").
Select("users.name, emails.email").
Joins("left join emails on emails.user_id = users.id").
Scan(&results)

3. Joins and Preload

One of the most useful features of Gorm is the automatic management of relations. The functions “Preload” and “Join” help to do this, but when is better to use one or the other?

The Joins function is optimized for one-to-one relations and it makes the query faster by directly adding the join to the query. Preload instead can be used in any case, but it first reads all the records and then manually updates the relations in the final result.

db.Preload("Orders").Find(&users)

db.Joins("Company").Joins("Manager").Joins("Account").First(&user, 1)

// You can't do this!
// db.Joins("Orders").Find(&users)
// because an user can have more than one order

4. Find and First

Find and first are both used to retrieve data, but there is a big difference between them in how they handle errors. By using “Find”, if no value is found an error is raised. Instead, if no rows are retrieved with “First” nothing happens. The value returned will be empty and the error nil.

db.First(&user) // an error is raised if the table is empty

db.Limit(1).Find(&user) // no error

5. AutoMigrate your model to always have the latest version

While working on your project it could happen that a new table or column are needed. Taking track of new changes can be difficult, but for this case, Gorm provides the Migrate function.

This function takes input from the model to create new tables and update the database accordingly. The approach is conservative, Gorm only does additions or updates of new functionalities.

db.AutoMigrate(&User{}, &Product{}, &Order{})

--

--

Francesco Pastore

An engineering student in Milan and a web developer for an IT company. Write about programming and cybersecurity topics.