Go项目的CRUD
开发项目时,如果用到数据库,难免需要CRUD,但是在go项目中如何进行CRUD呢?这里分享下我的经验。
开发项目难免需要CRUD,但是在go项目中如何进行CRUD呢?这里分享下我的经验。
下面以一个项目中的一个system模块为例,文件组织如下:
├── system
│ ├── dao
│ │ ├── dao.go
│ │ ├── dao_test.go
│ │ └── user.go
│ ├── dao_mock.go
│ ├── dao.go
│ ├── model
│ │ └── user.go
│ ├── service
│ │ ├── service.go
│ │ ├── service_test.go
│ │ ├── user_test.go
│ │ └── user.go
│ ├── service_mock.go
│ └── service.go
- /system: 模块,一个中大型项目有多个模块,例如:system、product、trade等
- /dao: 这个目录存放数据库操作相关的文件,例如:user.go、role.go、menu.go等
- /dao/dao.go: 定义了Dao结构体和实例化方法
- /dao/user.go:操作user表相关的方法
- /model:model目录存放system模块需要用到的所有结构体
- /model/user.go: 用户数据相关结构体,例如:表Schema结构体、FindUserFilter结构体、user对外的参数结构体等
- /dao.go: 定义数据库操作对外的接口
这里只讲数据库相关,不涉及service.go、service/等
一、dao.go
dao.go 定义了DAO接口,所有的数据库操作都需要先在DAO中定义。
dao.go 的顶部使用go:generate 生成到 dao_mock.go,这样service中写单元测试时,可以不需要连接数据库。
//go:generate mockgen -source $GOFILE -destination ./dao_mock.go -package $GOPACKAGE
package system
import (
"context"
"xxx/internal/module/system/model"
)
type DAO interface {
CreateUser(ctx context.Context, m *model.User) error
UpdateUsers(ctx context.Context, filter *model.FindUserFilter, update map[string]any) (int64, error)
UpdateUser(ctx context.Context, m *model.User, update map[string]any) error
CountUsers(ctx context.Context, filter *model.FindUserFilter) (int64, error)
FindUsers(ctx context.Context, filter *model.FindUserFilter) ([]*model.User, error)
FindUserByID(ctx context.Context, id int64) (*model.User, error)
FindUser(ctx context.Context, filter *model.FindUserFilter) (*model.User, error)
DeleteUsers(ctx context.Context, filter *model.FindUserFilter) error
}
二、model/user.go
package model
import (
"strings"
"github.com/samber/lo"
"xxx/internal/pkg/db"
)
type User struct {
db.Model
Username string
Nickname string
Phone string
Email string
Gender string
Roles string
Password string
Status UserStatus
}
func (User) TableName() string {
return TableUsers
}
type FindUserFilter struct {
db.BaseFilter
ID db.F[int64]
IDs db.F[[]int64] `gorm:"column:id"`
Username db.F[string]
Phone db.F[string]
Nickname db.F[string]
Gender db.F[string]
Email db.F[string]
Status db.F[UserStatus]
}
type CreateUserRequest {
// TODO
}
type UpdateUserRequest {
// TODO
}
其中 User结构体对应数据库的User Schema,所有的字段都定义在里面。
而FindUserFilter结构体是FindUser、UpdateUser、DeleteUser时需要传递的参数例如
s.dao.FindUser(ctx, model.FinUserFilter{
Username: db.Eq("zhangsan"),
Status: db.Eq("disable"),
Gender: db.Ne("femal")
})
三、/dao
1、 dao/dao.go
package dao
import (
"github.com/samber/do/v2"
"xxx/internal/module/system"
)
type Dao struct {
}
func New(i do.Injector) (system.DAO, error) {
return &Dao{}, nil
}
dao.go 定义了Dao结构体,并提供了 依赖注入的New方法。
2 dao/user.go
package dao
import (
"context"
"xxx/internal/module/system/model"
"xxx/internal/pkg/db"
)
func (d *Dao) CreateUser(ctx context.Context, m *model.User) error {
return db.GetDB(ctx).Create(m).Error
}
func (d *Dao) UpdateUsers(ctx context.Context, filter *model.FindUserFilter, update map[string]any) (int64, error) {
return db.Updates(ctx, &model.User{}, filter, update)
}
func (d *Dao) UpdateUser(ctx context.Context, m *model.User, update map[string]any) error {
return db.Update(ctx, m, update)
}
func (d *Dao) CountUsers(ctx context.Context, f *model.FindUserFilter) (total int64, err error) {
return db.Count(ctx, &model.User{}, f)
}
func (d *Dao) FindUsers(ctx context.Context, f *model.FindUserFilter) (ms []*model.User, err error) {
err = db.Find(ctx, f, &ms)
return
}
func (d *Dao) FindUser(ctx context.Context, f *model.FindUserFilter) (*model.User, error) {
var m model.User
if err := db.FindOne(ctx, f, &m); err != nil {
return nil, err
} else {
return &m, nil
}
}
func (d *Dao) FindUserByID(ctx context.Context, id int64) (m *model.User, err error) {
return d.FindUser(ctx, &model.FindUserFilter{ID: db.Eq(id)})
}
func (d *Dao) DeleteUsers(ctx context.Context, filter *model.FindUserFilter) error {
_, err := db.Delete(ctx, &model.User{}, filter)
return err
}
最后修改于 2025-06-09
此篇文章的评论功能已经停用。