SoFunction
Updated on 2025-03-01

golang Gorm framework explanation

introduce

1.1 Introduction

Full function ORM
Related (Has One,Has Many,Belongs To,Many To Many,Polymorphic,Single table inheritance)
Create,Save,Update,Delete,Find Hook method
support Preload、Joins Preloading
Transactions,嵌套Transactions,Save Point,Rollback To Saved Point
Context,Precompiled mode,DryRun model
Batch Insert,FindInBatches,Find/Create with Map,use SQL expression、Context Valuer conduct CRUD
SQL Builder,Upsert,Database lock,Optimizer/Index/Comment Hint,Named Parameters,Subquery
Compound primary key,index,constraint
Auto Migration
Customize Logger
Flexible extensible plug-ins API:Database Resolver(Multi-database,Read and write separation)、Prometheus…
Each feature has been tested
Developer friendly

1.2 Installation

go get -u /gorm
go get -u /driver/sqlite

2. Use

2.1 Create a table

package main

import (
	"fmt"

	"/driver/mysql"
	"/gorm"
)

//Model Structuretype Student struct {
	Id   int
	Name string
	Age  int
}

type User struct {
	
	Name string `gorm:"type:varchar(20);not null"`
	Telephone string `gorm:"varchar(110;not null;unique"`
	Password string `gorm:"size:255;not null"`
}
func main() {
	// Use dsn to connect to the database, the database pool comes with Grom	//Account: Password@Connection method (ip address: port number)/Database?  Language, time zone (8-hour system is adopted if the time zone is not set)	dsn := "root:mysql@tcp(127.0.0.1:3306)/gotest?charset=utf8mb4&parseTime=True&loc=Local"
	conn, err := ((dsn), &{}) //Use mysq to connect to the database, the second parameter can add more configuration (optional)	if err != nil {
		(err)
	}
	(&Student{}) //Create a table? Determine whether the table structure exists}

//Multi-table creation(&Company{}, &Worker{})

2.2. Add data

stu := &Student{
		Id:   3,
		Name: "li333",
		Age:  30,
	}
	res := (stu) //Insert data into the database, its return value has only one type, no error type	//Note: If the above is written as stu := Student{...}, then it is written as Create(&stu)
	if  != nil { //Add to determine whether the data is inserted?		()
	}

2.3. Query data

var student Student
	//Query First query one	(&student)
	(student)
	()
	//Condition query	res := (&student, "name=? and id=?", "yang", 1)
	(res)
 //Query all Find	var stu []Student
	("students").Find(&stu)
	for _, v := range stu {
		()
	}

 // IN
	var students []Student
	("students").Where("name IN ?", []string{"abc", "bili"}).Find(&students)
	(students)

	// LIKE
	("name LIKE ?", "%jin%").Find(&users)

	// AND
	("name = ? AND age >= ?", "jinzhu", "22").Find(&users)

	// Time
	("updated_at > ?", (2022,05,20,0,0,0,0,&{})).Find(&users)

	// BETWEEN
	("created_at BETWEEN ? AND ?", (2022,05,20,0,0,0,0,&{}), ()).Find(&users)

2.4 Update data

  //Update data	("students").Where("id=?", 1).Update("name", "ttt")
	("students").Where("id=?", 2).Updates(&Student{Name: "bili", Age: 10})
	//Press the primary key to update, pass in the structure object, and update the corresponding content according to the corresponding primary key  ("user").Save(&user1)

2.5 Delete data

("students").Where("id=?", 1).Delete(&Student{})

2.6 Execute native sql

("select * from students where id=?", 3).Scan(&student)
(student)

("DROP TABLE users")
("UPDATE orders SET shipped_at=? WHERE id IN ?", (), []int64{1,2,3})

3. One-to-one

3.1 Create a table

package main

import (
	"fmt"

	"/driver/mysql"
	"/gorm"
)

type User struct {
	
	CreditCard CreditCard
	Name       string
}

type CreditCard struct {
	
	Number string
	UserID uint
}

func main() {
	// Use dsn to connect to the database, the database pool comes with Grom	//Account: Password@Connection method (ip address: port number)/Database?  Language, time zone (8-hour system is adopted if the time zone is not set)	dsn := "root:mysql@tcp(127.0.0.1:3306)/crow?charset=utf8mb4&parseTime=True&loc=Local"
	conn, err := ((dsn), &{}) //Use mysq to connect to the database, the second parameter can add more configuration (optional)	if err != nil {
		(err)
	}
	(&User{})
	(&CreditCard{})

	//Create a table? Determine whether the table structure exists	user := &User{
		Name: "Li Si",
	}

	(user)

	card := &CreditCard{
		Number: "123",
		UserID: 1,
	}
	(card)

}

3.2 Polymorphic association

//Polymorphic association//GORM provides polymorphic association support for has one and has many, which saves the table name and primary key value of the owner entity into fields of polymorphic type.
type Cat struct {
  ID    int
  Name  string
  Toy   Toy `gorm:"polymorphic:Owner;"`
}

type Dog struct {
  ID   int
  Name string
  Toy  Toy `gorm:"polymorphic:Owner;"`
}

type Toy struct {
  ID        int
  Name      string
  OwnerID   int
  OwnerType string
}

(&Dog{Name: "dog1", Toy: Toy{Name: "toy1"}})
// INSERT INTO `dogs` (`name`) VALUES ("dog1")
// INSERT INTO `toys` (`name`,`owner_id`,`owner_type`) VALUES ("toy1","1","dogs")

3.3 Foreign Key Constraints

You can use the tagconstraintConfigurationOnUpdateOnDeleteImplement foreign key constraints, which are created when migrating using GORM, for example:

type User struct {
  
  Name      string
  CompanyID int
  Company   Company `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}

type Company struct {
  ID   int
  Name string
}

4. One-to-many

Has Many
has many establish a one-to-many connection with another model. Unlike has one, owners can have zero or more correlation models.

For example, your application contains user and credit card models, and each user can have multiple credit cards.

// User has multiple CreditCards, UserID is a foreign keytype User struct {
  
  CreditCards []CreditCard
}

type CreditCard struct {
  
  Number string
  UserID uint
}
package main

import (
	"fmt"

	"/driver/mysql"
	"/gorm"
)


type User struct {
	
	MemberNumber string       `gorm:"varchar(110;not null;unique"`
	CreditCards  []CreditCard `gorm:"foreignKey:UserNumber;references:MemberNumber"`
	Name         string
}

type CreditCard struct {
	
	Number     string
	UserNumber string `gorm:"varchar(110;not null;unique"`
}

func main() {
	// Use dsn to connect to the database, the database pool comes with Grom	//Account: Password@Connection method (ip address: port number)/Database?  Language, time zone (8-hour system is adopted if the time zone is not set)	dsn := "root:mysql@tcp(127.0.0.1:3306)/crow?charset=utf8mb4&parseTime=True&loc=Local"
	conn, err := ((dsn), &{}) //Use mysq to connect to the database, the second parameter can add more configuration (optional)	if err != nil {
		(err)
	}
	(&User{}, &CreditCard{})
	user := User{
		Name:         "ttt3",
		MemberNumber: "1003",
	}
	(&user)
	card := CreditCard{
		Number:     "111",
		UserNumber: ,
	}
	(&card)

}


5. Many-to-many

Many To Many

Many to Many will add a join table to both models.

For example, your application includes user and language, and one user can say multiple languages, and multiple users can also say one language.

// User owns and belongs to multiple languages, `user_languages` is the connection tabletype User struct {
  
  Languages []Language `gorm:"many2many:user_languages;"`
}

type Language struct {
  
  Name string
}

When using GORMAutoMigrateforUserWhen creating a table, GORM automatically creates the connection table

Backreferences

// User owns and belongs to multiple languages, `user_languages` is the connection tabletype User struct {
  
  Languages []*Language `gorm:"many2many:user_languages;"`
}

type Language struct {
  
  Name string
  Users []*User `gorm:"many2many:user_languages;"`
}

Rewrite foreign keys

formany2manyRelationship, joining tables will have foreign keys for two models at the same time, for example:

type User struct {
  
  Languages []Language `gorm:"many2many:user_languages;"`
}

type Language struct {
  
  Name string
}

// Join Table: user_languages
//   foreign key: user_id, reference: 
//   foreign key: language_id, reference: 

To rewrite them, you can use the tagsforeignKeyreferencejoinforeignKeyjoinReferences. Of course, you don't need to use all tags, you can only use one of the foreign keys and references to rewrite the part.

type User struct {
    
    Profiles []Profile `gorm:"many2many:user_profiles;foreignKey:Refer;joinForeignKey:UserReferID;References:UserRefer;JoinReferences:UserRefer"`
    Refer    uint
}

type Profile struct {
    
    Name      string
    UserRefer uint
}

// The connection table will be created: user_profiles//   foreign key: user_refer_id, reference: 
//   foreign key: profile_refer, reference: profiles.user_refer

Self-cited Many2Many

Self-cited many2many relationship

type User struct {
  
    Friends []*User `gorm:"many2many:user_friends"`
}

// The connection table will be created: user_friends//   foreign key: user_id, reference: 
//   foreign key: friend_id, reference: 

6. Obtain multi-table data

Preload

GORM allowsPreloadOther SQL directly load relationships, such as:

type User struct {
  
  Username string
  Orders   []Order
}

type Order struct {
  
  UserID uint
  Price  float64
}

// Preload related Order when searching for user("Orders").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4);

("Orders").Preload("Profile").Preload("Role").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4); // has many
// SELECT * FROM profiles WHERE user_id IN (1,2,3,4); // has one
// SELECT * FROM roles WHERE id IN (4,5,6); // belongs to

Joins Preload

PreloadLoad associated data in a separate query. andJoin PreloadThe associated data will be loaded using inner join, for example:

("Company").Joins("Manager").Joins("Account").First(&user, 1)
("Company").Joins("Manager").Joins("Account").First(&user, " = ?", "jinzhu")
("Company").Joins("Manager").Joins("Account").Find(&users, " IN ?", []int{1,2,3,4,5})

Notice Join PreloadSuitable for one-to-one relationships, for example:has one, belongs to

Preload all

Used when creating and updatingSelectsimilar,Can also be withPreloadUse together, it can be usedPreloadAll associations, for example:

type User struct {
  
  Name       string
  CompanyID  uint
  Company    Company
  Role       Role
}

().Find(&users)

Preload with conditions

GORM allows conditional Preload associations, similar toInline conditions

// Preload Order with conditions("Orders", "state NOT IN (?)", "cancelled").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4) AND state NOT IN ('cancelled');

("state = ?", "active").Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
// SELECT * FROM users WHERE state = 'active';
// SELECT * FROM orders WHERE user_id IN (1,2) AND state NOT IN ('cancelled');

Custom preload SQL

You canfunc(db *) *Implement custom preload SQL, for example:

("Orders", func(db *) * {
  return (" DESC")
}).Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4) order by  DESC;

Nested preload

GORM supports nested preloading, for example:

("").Preload("CreditCard").Find(&users)

// Customize the conditions for preloading `Orders`// In this way, GORM will not load mismatched order records("Orders", "state = ?", "paid").Preload("").Find(&users)

This is all about this article about golang Gorm framework. For more related golang Gorm framework content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!