Gorm level UP: how to upgrade and start to use Gorm v2

Michael Ushakov
4 min readFeb 10, 2022

--

Comparing Gorm v1 with Gorm v2 is like comparing the mighty Gorgon with the regular one.

Many people use this ORM to interact with their databases, which is completely understandable, because working with ORM is very convenient. I personally use it in most of my projects and only occasionally resort to raw SQL when it’s absolutely necessary. Today we gonna yet again talk about GORM. I already covered my experience working with the first version in my previous article which you can find here. I wrote this article specifically for those of you who still use the first version and would like to migrate to the second one. That’s exactly what we gonna do here. Before we begin I would like to encourage all of you to subscribe to our media: Medium, Twitter.

About GORM versions

Some of you might ask yourself why migrate to the next version? Well, to put it lightly, because the current one is broken and some of its bugs are so severe it takes a lot of effort to actually make it work the way you want. If you’d like to learn more about it, follow the link.

Golang packages are being distributed using VCS repositories, lots of them are being hosted on github, including Gorm v1. A Package version must conform to a certain format: “major.minor.patch”. You got to use all three parts, otherwise its gonna be replaced with a pseudo version which looks like this “v.0.0.0-{timestamp}-{commithash}”. For example, v0.0.0–20191109021931-daa7c04131f5. And keep in mind that major can only be 0 or 1, if it’s not, to import this package you gonna have to use something like this “github.com/wissance/gwuu/v2”. For some reason, the author of GORM decided to host Gorm v2 elsewhere (gorm.io). Because of that, for quite awhile, I couldn’t figure why some tutorials work and the others dont. Turns out, they didn’t bother to put version numbers in the description. If you want a complete GORM tutorial, like and subscribe to our channel. We need at least 500 subscribers and 200 likes to make it happen.

Just in case, here are two repositories for v1 and v2 respectively:

* gorm v1 — github.com/jinzhu/gorm

* gorm v2 — gorm.io/gorm

So why migrate to version 2.0? Let’s try to figure this out together.

The difference between Gorm v1 and Gorm v2

The first and the most prominent advantage of Gorm v2 is, you can actually close a connection using Close() method. There are different ways to work with external resources your application has no control over:

  • A Short living connection, as in open, interact and close;
  • A persistent connection;

Using short living connections with Postgres in my web applications I encountered the following problem — at some point, my application would just stop connecting to the database. It turns out that Gorm v1 didn’t close the connections and my only option was to restart Postgres whenever that happens.

Here is what happens to Postgres connections if you use Gorm v1 and call Close() after every business logic operation.

Gorm v2 closes connections just fine, so it’s no longer an issue.

// Auto migrate & set up relations

func PrepareDb(db *gorm.DB) { // Auto migrate
db.AutoMigrate(&RuntimeType{}, &Runtime{}, &EnvironmentType{},
&Environment{}, &EnvironmentValue{}, &Function{}, &Group{}, &Tag{})
db.Model(Runtime{}).AddForeignKey(“runtime_type_id”,
“runtime_types(id)”, “CASCADE”,
“CASCADE”)

db.Model(Environment{}).AddForeignKey(“type_id”,
“environment_types(id)”,
“CASCADE”, “CASCADE”)
db.Model(EnvironmentValue{}).AddForeignKey(“environment_id”,
“environments(id)”,
“CASCADE”,
“CASCADE”)
db.Model(EnvironmentValue{}).AddForeignKey(“function_id”,
“functions(id)”,
“CASCADE”,
“CASCADE”)
db.Model(Function{}).AddForeignKey(“runtime_id”, “runtimes(id)”,
“CASCADE”, “CASCADE”) }

db.Model(Function{}).AddForeignKey(“group_id”, “groups(id)”, “SET
NULL”, “CASCADE”)
db.Table(“functions”).AddForeignKey(“function_id”, “functions(id)”,
“CASCADE”, “CASCADE”)
db.Table(“function_tags”).AddForeignKey(“tag_id”, “tags(id)”, “CASCADE”,
“CASCADE”)

As you can see in the above example, adding foreign keys happens through calling AddForeignKey methods. Creating a many-to-many relationship in gorm v1 looks even worse. To create such a relationship it’s necessary to directly access the tables through db.Table. In gorm v2 this problem has been fixed. Now all you got to do to create the relationship is to add the corresponding annotations to your model:

type Function struct {
gorm.Model
// ID uint `gorm:”primary_key; AUTO_INCREMENT”`
Name string `gorm:”type:varchar(255);not null;unique;”`
DisplayName string `gorm:”type:varchar(255);not null;”`
FunctionCodeFile string `gorm:”type:varchar(512);not null;”`
Runtime Runtime `gorm:”foreignkey:RuntimeID;”`
RuntimeID uint `gorm:”not null;”`
Tags []Tag `gorm:”many2many:function_tags;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;”`
GroupId sql.NullInt32 `gorm:”default:null;”`
Group Group `gorm:”foreignkey:GroupId;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;”`
Version string `gorm:”type:varchar(32);not null;default:’’;”`
Timeout int `gorm:”type:int;not null;default:0;”`

It’s probably one of the most important changes (along with a transaction function syntax, removal of certain functions, etc). It seems to me that switching to Gorm v2 is completely justified because it eliminates a lot of problems which should have been fixed in Gorm v1. In this modular test you can find a little example of a simple data model interacting with Gorm v2.

Conclusion

I cannot say I am a fan of using everything brand new. In my opinion, it’s only justified to upgrade when it gives you considerable advantages and switching from Gorm v1 to Gorm v2 does exactly that! Thank you for reading!

--

--

Michael Ushakov

I am a scientist (physicist), an engineer (hardware & software) and the CEO of Wissance (wissance.com)