In-depth understanding of Beego ORM: principles and examples

Beego ORM Description

Official Documentation - Quick Start
Beego ORM (Object Relational Mapping) is a module in the Beego framework that is used to establish a mapping relationship between the application's data model and database tables, allowing developers to perform database operations through Go language code , without having to write SQL query statements directly.

Some basic principles and features of Beego ORM

1. Define the data model:type User struct {}

Developers need to define a data model, usually a structure in the Go language, with each field representing a column of the database table. Use tags in the structure to specify the mapping relationship between fields and database tables, including column names, data types, etc.

type User struct {
    
    
	ID           int       `orm:"column(id);auto"`
	UserAccount  string    `orm:"column(userAccount);unique"` //为单个字段增加 unique键
	UserRole     string    `orm:"column(userRole);default(user)"`
	UserName     string    `orm:"column(userName);null"`
	UserAvatar   string    `orm:"column(userAvatar);null"`
	Gender       int8      `orm:"column(gender);null"`
	UserPassword string    `orm:"column(userPassword)"`
	CreateTime   time.Time `orm:"column(createTime);auto_now_add;type(datetime)"` //auto_now_add 第一次保存时才设置时间
	UpdateTime   time.Time `orm:"column(updateTime);auto_now;type(datetime)"`     //auto_now 每次model保存时都会对时间自动更新
	IsDelete     int32     `orm:"column(isDelete)"`
	Test         string    `orm:"-"` //- 即可忽略模型中的字段
}
// 设置引擎为 INNODB
func (u *User) TableEngine() string {
    
    
	return "INNODB"
}

2. Register the model:orm.RegisterModel(new(User))

Developers need to register the defined data model into the ORM so that the ORM knows which data tables to operate and the structure of the data tables.

orm.RegisterModel(new(User))

3. Register database connection:orm.RegisterDataBase("default", "mysql", "user:pwd@tcp(mysql)/dbname?charset=utf8&parseTime=true")

Developers need to configure database connection information, including database type, connection string, etc. The ORM uses this information to connect to the database.

orm.RegisterDataBase("default", "mysql", "user:pwd@tcp(mysql)/dbname?charset=utf8&parseTime=true")

4. Database table structure synchronization:orm.RunSyncdb("default", false, true)

When the application starts, the ORM can automatically check whether the database table structure is consistent with the definition of the data model. If it is inconsistent, you can choose to automatically update the database table structure to be consistent with the data model.

err := orm.RunSyncdb("default", false, true)
if err != nil {
    
    
	fmt.Println("数据库表结构同步操作失败 err=", err.Error())
}

5. Create ORM object:o = orm.NewOrm()

o = orm.NewOrm()

6. Database operations:o.Insert(XXX)

Developers can use the methods provided by the ORM to perform database operations, including insert, query, update, and delete operations. ORM converts these operations into corresponding SQL query statements and performs database operations.

func Add() int64 {
    
    
	// 创建了一个新的 User 模型对象,准备插入到数据库中。
	user := new(User)
	user.UserAccount = "xiaoxiong"

	// 执行数据库插入操作,将 user 对象插入到数据库中。num 变量表示插入的记录数,err 变量表示操作中的任何错误。
	num, err := O.Insert(user)
	if err != nil {
    
    
		fmt.Println("数据库插入操作失败[o.Insert(user)] err=", err.Error())
	}
	fmt.Println("数据库插入操作成功[o.Insert(user) succeed] num=", num)
	return num
}

func GetById(id int64) (*User, error) {
    
    
	qs := O.QueryTable(new(User))

	var userInfo User
	err := qs.Filter("id", id).Filter("isDelete", 0).One(&userInfo) //注意这里不能是 var userInfo *User,否则报错
	if err == orm.ErrMultiRows {
    
    
		fmt.Printf("user 表中存在 id=[%d] 的多条记录, qs.One err=[%v] \n", id, err.Error())
		return nil, err
	}
	if err == orm.ErrNoRows {
    
    
		fmt.Printf("user 表没有找到 id=[%d] 的记录, qs.One err=[%v] \n", id, err.Error())
		return nil, err
	}
	return &userInfo, nil
}

6. Transaction support:

ORM provides transaction support, and developers can use transactions to ensure that a series of database operations either all succeed or all fail to maintain data consistency.

Official Documentation - Affairs

7. Define filters and hooks:orm.AddGlobalFilterChain(builder.FilterChain)

ORM allows developers to define filters and hook functions to perform specific logic before and after data manipulation. These filters and hooks can be used to implement functions such as validation, default value setting, etc.

builder := bean.NewDefaultValueFilterChainBuilder(nil, true, true)
orm.AddGlobalFilterChain(builder.FilterChain)

8. Establish mapping relationships between different tables:

ORM can establish mapping relationships between different tables, including one-to-one, one-to-many, many-to-one, many-to-many, etc. relationships, making it easier to perform complex data queries and operations.

Official document - association table query

9. Cache support:

Some ORM frameworks provide caching support and can cache database query results to improve query performance.

Summarize

The principle of ORM is to establish a mapping relationship between the data model and the database table, and provide a set of methods to perform database operations to simplify the process of developers interacting with the database and reduce the work of manually writing SQL query statements.
ORM improves development efficiency and reduces the complexity of database operations by mapping object operations to underlying database operations . Different programming languages ​​and frameworks have their own ORM implementations, but the basic principles are similar.

Sample code

Source code address: GitHub

package main

import (
	"fmt"
	_ "simple-orm-bee/routers"
	"time"

	"github.com/beego/beego/v2/client/orm"
	"github.com/beego/beego/v2/client/orm/filter/bean"
	beego "github.com/beego/beego/v2/server/web"
	_ "github.com/go-sql-driver/mysql"
)

type User struct {
    
    
	//orm 为字段设置 DB 列的名称
	ID           int       `orm:"column(id);auto"`            //auto显示指定一个字段为自增主键,该字段必须是 int, int32, int64, uint, uint32, 或者 uint64
	UserAccount  string    `orm:"column(userAccount);unique"` //为单个字段增加 unique键
	AccessKey    string    `orm:"column(accessKey);index"`    //为单个字段增加索引
	SecretKey    string    `orm:"column(secretKey)"`
	UserRole     string    `orm:"column(userRole);default(admin)"`
	UserName     string    `orm:"column(userName);null"` //null代表ALLOW NULL
	UserAvatar   string    `orm:"column(userAvatar);null"`
	Gender       int8      `orm:"column(gender);null"`
	UserPassword string    `orm:"column(userPassword)"`
	CreateTime   time.Time `orm:"column(createTime);auto_now_add;type(datetime)"` //auto_now_add 第一次保存时才设置时间
	UpdateTime   time.Time `orm:"column(updateTime);auto_now;type(datetime)"`     //auto_now 每次model保存时都会对时间自动更新
	IsDelete     int32     `orm:"column(isDelete)"`
	Test         string    `orm:"-"` //- 即可忽略模型中的字段
}

// 设置引擎为 INNODB
func (u *User) TableEngine() string {
    
    
	return "INNODB"
}

// 自定义表名
func (u *User) TableName() string {
    
    
	return "user"
}

var O orm.Ormer

func init() {
    
    
	// 注册 ORM 模型。new(User) 创建了一个新的 User 模型对象并注册到 ORM 中。这样 ORM 知道了要操作哪个数据表和数据表的结构。
	orm.RegisterModel(new(User))

	// 注册默认的数据库连接。告诉 ORM 使用 MySQL 数据库,数据库连接字符串为 "root:xxx",并且指定了连接别名为 "default"。这个连接别名会在后续的数据库操作中使用。
	orm.RegisterDataBase("default", "mysql", "root:@tcp(127.0.0.1:3306)/xapi?charset=utf8")

	// 创建一个 ORM 对象 o,用于执行数据库操作。
	O = orm.NewOrm()
}
func main() {
    
    
	// 执行数据库表结构同步操作。告诉 ORM 在默认数据库连接上执行同步操作,第二个参数 false 表示不强制删除已存在的表,第三个参数 true 表示打印同步操作的日志。这通常在应用程序启动时执行,以确保数据库表结构与 ORM 模型定义一致。
	err := orm.RunSyncdb("default", false, true)
	if err != nil {
    
    
		fmt.Println("数据库表结构同步操作失败[orm.RunSyncdb] err=", err.Error())
	}

	// 创建一个默认值过滤器链构建器。默认值过滤器用于在插入数据时为字段设置默认值。这里创建了一个新的构建器,第二个参数 true 表示启用默认值过滤器,第三个参数 true 表示打印过滤器日志。
	builder := bean.NewDefaultValueFilterChainBuilder(nil, true, true)
	// 将默认值过滤器链添加到全局过滤器链中,以便在插入数据时应用默认值过滤器。
	orm.AddGlobalFilterChain(builder.FilterChain)

	id := Add()

	userinfo, err := GetById(id)
	if err == nil {
    
    
		fmt.Println("userinfo=", userinfo)
	}

	beego.Run()
}

func GetById(id int64) (*User, error) {
    
    
	qs := O.QueryTable(new(User))

	var userInfo User
	err := qs.Filter("id", id).Filter("isDelete", 0).One(&userInfo) //注意这里不能是 var userInfo *User,否则报错
	if err == orm.ErrMultiRows {
    
    
		fmt.Printf("user 表中存在 id=[%d] 的多条记录, qs.One err=[%v] \n", id, err.Error())
		return nil, err
	}
	if err == orm.ErrNoRows {
    
    
		fmt.Printf("user 表没有找到 id=[%d] 的记录, qs.One err=[%v] \n", id, err.Error())
		return nil, err
	}
	return &userInfo, nil
}

func ListByIds(ids []int64) ([]*User, error) {
    
    
	qs := O.QueryTable(new(User))

	var users []*User
	qs = qs.Filter("id__in", ids).Filter("isDelete", 0)
	_, err := qs.All(&users) //这里可以是 var users []*User 或者 var users []User
	if err != nil {
    
    
		fmt.Printf("User ListByIds qs.All error: %v \n", err.Error())
		return users, err
	}
	return users, nil
}

func Add() int64 {
    
    
	// 创建了一个新的 User 模型对象,准备插入到数据库中。
	user := new(User)
	user.UserAccount = "xiaoxiong"

	// 执行数据库插入操作,将 user 对象插入到数据库中。num 变量表示插入的记录数,err 变量表示操作中的任何错误。
	num, err := O.Insert(user)
	if err != nil {
    
    
		fmt.Println("数据库插入操作失败[o.Insert(user)] err=", err.Error())
	}
	fmt.Println("数据库插入操作成功[o.Insert(user) succeed] num=", num)
	return num
}

Guess you like

Origin blog.csdn.net/trinityleo5/article/details/133385516