gormt中分页查询的使用
Posted jiangxiaoju
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了gormt中分页查询的使用相关的知识,希望对你有一定的参考价值。
原创不易,未经允许,请勿转载。
文章目录
gormt的Github链接
最近因为项目需要,所以使用了gormt
这个项目,用来自动生成struct等代码。但是美中不足的是它里面生成的一些函数不支持分页查询,所以我就参考之前Java
使用的Mybatis-Plus
中的分页插件,在gormt
中实现了对分页查询的支持。当需要进行分页查询的操作时,我们只需要传入每个分页的大小、当前的页数(从1开始计算),以及排序条件、筛选条件即可,不需要再去关心偏移量等一些复杂的操作。
接下来我简单介绍一下增加的内容以及如何使用
如何使用?
分页查询的功能默认是开启的,IPage
和Page
的内容在生成的gen.page.go文件中,SelectPage函数则是在dbname.gen.tablename.go文件中
可以通过配置文件中的这个选项选择是否开启
is_out_page: true # 是否输出分页函数
IPage接口的介绍
这里提供了一个IPage接口,定义了以下方法,作用如注释所示
type IPage interface
GetRecords() interface // 获取查询的记录
SetRecords(interface) // 设置查询的记录
GetTotal() int64 // 获取总记录数
SetTotal(int64) // 设置总记录数
GetCurrent() int64 // 获取当前页
SetCurrent(int64) // 设置当前页
GetSize() int64 // 获取每页显示大小
SetSize(int64) // 设置每页显示大小
AddOrderItem(OrderItem) // 设置排序条件
AddOrderItems([]OrderItem) // 批量设置排序条件
GetOrederItemsString() string // 将排序条件拼接成字符串
Offset() int64 // 获取偏移量
GetPages() int64 // 获取总的分页数
在IPage
的基础上,提供了一个默认实现Page
,它实现了IPage
中的所有方法。
type Page struct
total int64 // 总的记录数
size int64 // 每页显示的大小
current int64 // 当前页
orders []OrderItem // 排序条件
Records interface // 查询数据列表
func (page *Page) GetRecords() interface
return page.Records
func (page *Page) SetRecords(records interface)
page.Records = records
func (page *Page) GetTotal() int64
return page.total
func (page *Page) SetTotal(total int64)
page.total = total
func (page *Page) GetCurrent() int64
return page.current
func (page *Page) SetCurrent(current int64)
page.current = current
func (page *Page) GetSize() int64
return page.size
func (page *Page) SetSize(size int64)
page.size = size
func (page *Page) AddOrderItem(orderItem OrderItem)
page.orders = append(page.orders, orderItem)
func (page *Page) AddOrderItems(orderItems []OrderItem)
page.orders = append(page.orders, orderItems...)
func (page *Page) GetOrederItemsString() string
arr := make([]string, 0)
var order string
for _, val := range page.orders
if val.asc
order = ""
else
order = "desc"
arr = append(arr, fmt.Sprintf("%s %s", val.column, order))
return strings.Join(arr, ",")
func (page *Page) Offset() int64
if page.GetCurrent() > 0
return (page.GetCurrent() - 1) * page.GetSize()
else
return 0
func (page *Page) GetPages() int64
if page.GetSize() == 0
return 0
pages := page.GetTotal() / page.GetSize()
if page.GetTotal()%page.size != 0
pages++
return pages
// 提供了一个构造方法,需要传入每个分页的大小,以及当前所处的页
func NewPage(size, current int64, orderItems ...OrderItem) *Page
return &Pagesize: size, current: current, orders: orderItems
在IPage
中OrderItem
是用作于排序的,定义如下,并且提供了两种构造方法
type OrderItem struct
column string // 需要排序的字段
asc bool // 是否正序排列,默认true
func BuildAsc(column string) OrderItem
return OrderItemcolumn: column, asc: true
func BuildDesc(column string) OrderItem
return OrderItemcolumn: column, asc: false
func BuildAscs(columns ...string) []OrderItem
items := make([]OrderItem, 0)
for _, val := range columns
items = append(items, BuildAsc(val))
return items
func BuildDescs(columns ...string) []OrderItem
items := make([]OrderItem, 0)
for _, val := range columns
items = append(items, BuildDesc(val))
return items
SelectPage函数的介绍
假设查询的表结构如下所示
type BlogAdmin struct
ID uint `gorm:"primaryKey;column:id;type:int unsigned;not null" json:"-"` // 用户ID
CreatedAt time.Time `gorm:"column:created_at;type:datetime;not null;default:CURRENT_TIMESTAMP" json:"createdAt"` // 创建时间
UpdatedAt time.Time `gorm:"column:updated_at;type:datetime;not null;default:CURRENT_TIMESTAMP" json:"updatedAt"` // 修改时间
DeletedAt *time.Time `gorm:"index:idx_deleted;column:deleted_at;type:datetime" json:"deletedAt"` // 删除时间
Username string `gorm:"unique;unique;column:username;type:varchar(255);not null" json:"username"` // 用户名
Password string `gorm:"column:password;type:varchar(255);not null" json:"password"` // 密码
下面是生成的对BlogAdmin
这个表的分页查询函数。一共需要传入两个参数
page
:实现了IPage
接口的类都可以,默认可以使用Page
opts
: 查询条件
返回值:
resultPage
:实现了IPage
接口,默认为Page
。查询的记录将保存将通过SetRecords
保存。err
:错误-
首先先获取出查询条件,根据查询条件,先查询出满足条件的记录,然后统计记录数,接着看是否需要排序,如果需要排序的话,则先进行排序操作。最后获取页面大小和偏移量,把查询结果保存到results
里面。
因为BlogAdmin
的表并未设置外键,所以下列代码中并未生成预加载部分的代码。
// SelectPage 分页查询
func (obj *_BlogAdminMgr) SelectPage(page IPage, opts ...Option) (resultPage IPage, err error)
options := options
query: make(map[string]interface, len(opts)),
for _, o := range opts
o.apply(&options)
resultPage = page
results := make([]BlogAdmin, 0)
var count int64 // 统计总的记录数
query := obj.DB.WithContext(obj.ctx).Model(BlogAdmin).Where(options.query)
query.Count(&count)
resultPage.SetTotal(count)
if len(page.GetOrederItemsString()) > 0
query = query.Order(page.GetOrederItemsString())
err = query.Limit(int(page.GetSize())).Offset(int(page.Offset())).Find(&results).Error
resultPage.SetRecords(results)
return
自定义IPage
如果说Page
不能满足您的使用需要的话,可以自定义一个IPage
的实现类。最简单的做法是继承Page
,然后定制您所需要的方法即可。
type MyPage struct
Page
...//一些拓展的字段
// 可以是新增的方法,也可以是重写Page实现好的方法,主要要使用指针类型
func (page *MyPage) someFunc(...)
...
假设现在有这么个需求,在前端分页展示的时候,我们不希望展示出所有的按钮,假设页面数量很多,但我们只需要固定展示10个分页按钮的话,效果如下。那单纯使用Page
就很难满足这个需求,还需要额外的一些处理。所以可以自定义IPage
的实现类,代码如下。
type MyPage struct
Page
begin int64 // 第一个分页按钮的页码
end int64 // 最后一个分页按钮的页码
showPages int // 展示的页面数
func (page *MyPage) setShowBtnNum()
if(page.GetPages() < page.showPages)
page.begin = 1
if page.GetPages() > 1
page.end = page.GetPages()
else
page.end = 1
else
page.begin = page.GetCurrent() - (page.showPages/2)
if page.showPages %2 == 0
page.end = page.GetCurrent() + (page.showPages/2 - 1)
else
page.end = page.GetCurrent() + page.showPages/2
if page.begin < 1
page.begin = 1
page.end = page.begin + page.showPages - 1;
if page.end > page.showPages
page.end = page.GetCurrent()
page.begin = page.end - (page.showPages - 1)
简单的使用案例
下面使用的结构体由下表生成的
https://github.com/xxjwxc/gormt/blob/master/data/view/genfunc/model/matrix.sql
func GetGorm(dataSourceName string) *gorm.DB
db, err := gorm.Open(mysql.Open(dataSourceName), &gorm.ConfigPrepareStmt: false)
if err != nil
panic(err)
sqlDB, err := db.DB()
if err != nil
panic(err)
// SetMaxIdleConns 设置空闲连接池中连接的最大数量
sqlDB.SetMaxIdleConns(10)
// SetMaxOpenConns 设置打开数据库连接的最大数量。
sqlDB.SetMaxOpenConns(100)
// SetConnMaxLifetime 设置了连接可复用的最大时间。
sqlDB.SetConnMaxLifetime(time.Hour)
return db.Debug()
// TestSelectPage 测试分页查询功能
func TestSelectPage(t *testing.T)
model.OpenRelated() // 打开全局预加载 (外键)
db := GetGorm("root:123456@tcp(192.168.253.100:3306)/gormt?charset=utf8&parseTime=True&loc=Local&interpolateParams=True")
defer func()
sqldb, _ := db.DB()
sqldb.Close()
()
accountMgr := model.AccountMgr(db)
// 构造分页条件
page := model.NewPage(1, 1)
// 不带条件的查询
result, err := accountMgr.SelectPage(page)
fmt.Println("不带条件查询")
fmt.Println(err)
fmt.Println(result.GetPages())
fmt.Println(result.GetTotal())
for _, val := range result.GetRecords().([]model.Account)
fmt.Println(val)
//带条件查询
page = model.NewPage(1, 2)
result, err = accountMgr.SelectPage(page, accountMgr.WithName("bbbb"))
fmt.Println("带条件查询")
fmt.Println(err)
fmt.Println(result.GetPages())
fmt.Println(result.GetTotal())
for _, val := range result.GetRecords().([]model.Account)
fmt.Println(val)
// 进行排序,按name字段降序
page = model.NewPage(1, 1, model.BuildDesc("name"))
result, err = accountMgr.SelectPage(page)
fmt.Println("进行排序,按name字段降序")
fmt.Println(err)
fmt.Println(result.GetPages())
fmt.Println(result.GetTotal())
for _, val := range result.GetRecords().([]model.Account)
fmt.Println(val)
gormt的Github链接
最近因为项目需要,所以使用了gormt
这个项目,用来自动生成struct等代码。但是美中不足的是它里面生成的一些函数不支持分页查询,所以我就参考之前Java
使用的Mybatis-Plus
中的分页插件,在gormt
中实现了对分页查询的支持。当需要进行分页查询的操作时,我们只需要传入每个分页的大小、当前的页数(从1开始计算),以及排序条件、筛选条件即可,不需要再去关心偏移量等一些复杂的操作。
接下来我简单介绍一下增加的内容以及如何使用
IPage和Page的内容在生成的gen.page.go文件中,SelectPage函数则是在dbname.gen.tablename.go文件中
IPage接口的介绍
这里提供了一个IPage接口,定义了以下方法,作用如注释所示
type IPage interface
GetRecords() interface // 获取查询的记录
SetRecords(interface) // 设置查询的记录
GetTotal() int64 // 获取总记录数
SetTotal(int64) // 设置总记录数
GetCurrent() int64 // 获取当前页
SetCurrent(int64) // 设置当前页
GetSize() int64 // 获取每页显示大小
SetSize(int64) // 设置每页显示大小
AddOrderItem(OrderItem) // 设置排序条件
AddOrderItems([]OrderItem) // 批量设置排序条件
GetOrederItemsString() string // 将排序条件拼接成字符串
Offset() int64 // 获取偏移量
GetPages() int64 // 获取总的分页数
在IPage
的基础上,提供了一个默认实现Page
,它实现了IPage
中的所有方法。
type Page struct
total int64 // 总的记录数
size int64 // 每页显示的大小
current int64 // 当前页
orders []OrderItem // 排序条件
Records interface // 查询数据列表
func (page *Page) GetRecords() interface
return page.Records
func (page *Page) SetRecords(records interface)
page.Records = records
func (page *Page) GetTotal() int64
return page.total
func (page *Page) SetTotal(total int64)
page.total = total
func (page *Page) GetCurrent() int64
return page.current
func (page *Page) SetCurrent(current int64)
page.current = current
func (page *Page) GetSize() int64 gormt中分页查询的使用