Manage Your Go Database Like a Pro with GORM

Kinanee Samson - Jul 12 - - Dev Community

No matter how much we say SQL is better than NoSQL, we can all agree that writing SQL by hand is not much fun, especially where you have to do joins and the rest. The need to solve this annoying issue has led to the development of several different ORMs (Object Relational Mapper) that sit as an abstraction layer on top of our database.

They provide developers a way to interact with data typically an SQL-compatible database using Objects and code instead of writing a bunch of SQL code. All programming languages have their ORM but in today's post we will take a brief look at GORM an ORM that is developed for Go or Go Lang as it is commonly called hence we are going to consider the following talking points;

  • Features of GORM
  • Installation and setup
  • Models
  • Add data
  • Read Data
  • Update Data
  • Delete Data

Features of GORM

GORM is a Full-Featured and developer-friendly ORM built with out-of-the-box support for all types of associations, and hooks that you can listen to extend the behavior of your models further. GORM is written in Go and supports multiple SQL-based databases like MySQL, SQL-Lite, Postgre SQL, and OracleDB. GORM has built-in support for Transactions, nested transactions, save points, and rollback to saved points. GORM allows us to run Batch Insert, FindInBatches, Find/Create with Map amongst others, let's see how we can install and setup GORM in a Go project.

Installation and Setup

To install GORM you need to run the following command;

go get -u gorm.io/gorm
Enter fullscreen mode Exit fullscreen mode

Next, you need to install a driver compatible with your SQL database and as such we will install the driver for MySQL with the following command.

go get -u gorm.io/driver/mysql
Enter fullscreen mode Exit fullscreen mode

Now we have GORM and a compatible SQL driver installed let's connect to a MySQL database.

package main

import (
  "gorm.io/driver/mysql"
  "gorm.io/gorm"
)


func main () {
    db, err := gorm.Open(mysql.New(mysql.Config{
        DSN: "root@tcp(localhost:3306)/test?charset=utf8mb4&parseTime=true",
    }))

    if err != nil {
        panic("failed to connect database")
    }
}
Enter fullscreen mode Exit fullscreen mode

Models

Models serve as a way to map a struct in your Go program to a database table. Each Model corresponds to a table in your database, while the keys on the struct correspond to columns on that table. While the values for each key serve as a row in your database. Let's create a User struct that will correspond to a user table.

import "gorm.io/gorm"

type User struct {
    gorm.Model,
    Name string `json:"name"`
    Email string `json:"email"`
}
Enter fullscreen mode Exit fullscreen mode

You can observe that each key on the struct has a type and that type will correspond to the type for that particular value on our SQL table. We can use other types like uint and bool. We can do things like specify foreign keys and unique columns.

import "gorm.io/gorm"

type User struct {
    gorm.Model,
    Name string `gorm:"type:varchar(20)" json:"name"`
    Email string `gorm:"unique;not null" json:"email"`
}
Enter fullscreen mode Exit fullscreen mode

You can embed the gorm.Model struct into your model struct. This adds commonly used fields like:

ID: A unique identifier for each record (usually the primary key).
CreatedAt: Automatically set to the current time when a record is created.
UpdatedAt: Automatically updated whenever a record is modified.
DeletedAt (optional): Used for soft deletes (marking records as deleted without physically removing them).

Add data

Let’s see how we can add data to our database using the model we just created.


// cont’d

func CreateUser (db *gorm.DB, name string, email string) User {
    newUser := User{
        Name: name,
        Email: email,
    }
    result := db.Create(&newUser)
    if result.Error != nil {
        panic("error creating user")
    }
    return newUser
}

user := CreateUser(db, "sam","sam@gmail.Com")
Enter fullscreen mode Exit fullscreen mode

The code above defines a function called CreateUser that takes a database connection (db), a name (name), and an email (email) as arguments and returns a User model. We can also create multiple users easily.


// cont’d

func CreateUsers(db *gorm.DB) []User {
    newUsers := []*User{
        {  Name: jay, Email: jay@gmail.Com  },
        {  Name: joe, Email: joe@gmail.Com  },
    }
    result := db.Create(&newUsers)
    if result.Error != nil {
        panic("error creating user")
    }
    return newUsers
}

users := CreateUsers(db)
Enter fullscreen mode Exit fullscreen mode

Read Data

Now we’ve created some data let’s see how we can read those data we just added.

// get single record

func GetUser(db *gorm.DB, id uint) User {
    user = User{
        ID: id
    }

    result := db.First(&user)
    if result.Error != nil {
        panic("Error fetching data")
    }
    return user
}

user := GetUser(db, 1)

Enter fullscreen mode Exit fullscreen mode

The code snippet above shows how to retrieve a single user, what if we are interested in getting multiple users?

// get single record

func GetUsers(db *gorm.DB) []User {
    var users []User
    result := db.Find(&users)
    if result.Error != nil {
        panic("Error fetching data")
    }
    return users
}

users := GetUsers(db);

Enter fullscreen mode Exit fullscreen mode

Update Data

Now we’ve seen how to read our data let’s see how we can update our data.

func UpdateUser(db *gorm.DB, id uint, name string) user {
    user := User{
        ID: id,
    }
    result := db.Find(&users).Update("name", name)
    if result.Error != nil {
        panic("Error fetching data")
    }
    return user
}

users := UpdateUser(db, 1, "sam");
Enter fullscreen mode Exit fullscreen mode

If we ware interested in updating multiple columns for a particular data we can use the following approach;

func UpdateUser(db *gorm.DB, id uint) user {
    user := User{
        Name: "phill"
        Email: "phill@gmail.com"
    }
    result := db.Where("id = ?", id).Updates(&user)
    if result.Error != nil {
        panic("Error fetching data")
    }
    return user
}

users := UpdateUser(db, 1);
Enter fullscreen mode Exit fullscreen mode

Delete Data

Now let’s see how we can delete a record or multiple records from our database


// delete single record

func DeleteUser(db *gorm.DB, id uint) {
    result := db.Delete(&User{}, id)
    if result.Error != nil {
        panic("Error fetching data")
     }
}

DeleteUser(db, 1)

// delete multiple records

func DeleteUsers(db *gorm.DB, ids []int{}) {
    result := db.Delete(&User{}, ids)
    if result.Error != nil {
        panic("Error fetching data")
     }
}
DeleteUsers(db, {1, 4, 10})
Enter fullscreen mode Exit fullscreen mode

That’s going to be all for this one guys, I hope you found this useful leave your thoughts in the comments section below.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .