新手参照 gorm 写的带模型关联的用户分页数据接口,求帮优化下

这几天上班没事做,看了下GO语言,试着写了下用户的分页接口,求指点优化下:

routers:

user := router.Group("user")
    {
        user.GET("/", controllers.UserIndex) // 是这个
        user.GET("/:id", controllers.UserShow)
        user.POST("/", controllers.UserStore)
        user.PUT("/:id", controllers.UserUpdate)
        user.DELETE("/:id", controllers.UserDestroy)
    }

controlers:

package controllers

import (
    "TongJiHouTai/gin/models"
    "github.com/gin-gonic/gin"
    "net/http"
    "strconv"
    "time"
)

func UserIndex(c *gin.Context) {
    phone := c.Query("phone")
    size, err := strconv.Atoi(c.DefaultQuery("size", "10"))
    page, err := strconv.Atoi(c.DefaultQuery("page", "1"))

    if err != nil {
        c.JSON(http.StatusOK, gin.H{
            "code":    500,
            "message": err.Error(),
        })
        return
    }

    var u models.User
    count := u.Count()
    var search models.UserSearch
    search.Page = page
    search.Size = size
    search.Phone = phone
    users, err := u.Page(search)

    if err != nil {
        c.JSON(http.StatusOK, gin.H{
            "code":    500,
            "message": err.Error(),
        })
        return
    }
    var response PageResponse
    response.Code = 0
    response.Message = "success"
    response.Data = users
    response.Total = count
    response.PerPage = size
    response.CurrentPage = page
    response.TotalPage = (count + size - 1) / size

    c.JSON(http.StatusOK, response)
}

models:

package models

import (
    "TongJiHouTai/gin/databases"
    "database/sql"
    "fmt"
    "time"
)

//首字母大写则该成员为公有成员(对外可见),否则是私有成员(对外不可见)
type User struct {
    Id             int        `gorm:"column:id; primary_key" json:"id"`
    Name           string     `gorm:"column:name" json:"name"`
    Pid            *int       `gorm:"column:pid" json:"-"`   // * 可匹配null
    Phone          string     `gorm:"column:phone" json:"phone"`
    Password       string     `gorm:"column:password" json:"-"` // - 表示输出json结果隐藏此字段
    Cid            *string    `gorm:"column:cid" json:"cid" json:"-"`
    IsRoot         int        `gorm:"column:is_root" json:"is_root"`
    LastLoginTime  *time.Time `gorm:"column:last_login_time" json:"-"`
    LastLogoutTime *time.Time `gorm:"column:last_logout_time" json:"-"`
    CreatedAt      *time.Time `gorm:"column:created_at" json:"created_at"`
    UpdatedAt      *time.Time `gorm:"column:updated_at" json:"-"`
    DeletedAt      *time.Time `gorm:"column:deleted_at" json:"-"` // - 表示输出json结果隐藏此字段
    Cids     []Cid  `json:"cids" gorm:"many2many:user_cids;ForeignKey:id;AssociationForeignKey:id"` // 多对多
    Roles    []Role `json:"roles" gorm:"many2many:user_roles;ForeignKey:id;AssociationForeignKey:id"` // 多对多
    Children []User `json:"children" gorm:"ForeignKey:pid;AssociationForeignKey:id"` // 1对多
    Parent   *User  `json:"parent" gorm:"ForeignKey:id;AssociationForeignKey:pid"` // 多对1
}

type JwtToken struct {
    Token string `json:"token"`
}

type UserSearch struct {
    Page  int    `json:"page"`
    Size  int    `json:"size"`
    Phone string `json:"phone"`
}

// 设置表名
func (User) TableName() string {
    return "users"
}

func (u *User) Page(search UserSearch) ([]*User, error) {
    var rows *sql.Rows

    query := databases.DB.Table("users").Debug()
    if search.Page > 0 {
            query = query.Order("id desc").Offset((search.Page - 1) * search.Size).Limit(search.Size)
        if search.Phone != "" {
            query = query.Where("phone LIKE ?", "%"+search.Phone+"%")
        }
    } else {
        query = query.Order("id desc")
        if search.Phone != "" {
            query = query.Where("phone LIKE ?", "%"+search.Phone+"%")
        }
    }

    rows, err := query.Rows()

    if err != nil {
        return nil, err
    }

    defer rows.Close()

    users := make([]*User, 0)

    for rows.Next() {
        var user User
        _ = databases.DB.ScanRows(rows, &user)

        query := databases.DB.Model(&user).Debug().
            Related(&user.Cids, "Cids").
            Related(&user.Roles, "Roles")

        if user.Pid != nil {
            query = query.Preload("Parent")
        } else {
            query = query.Preload("Children")
        }

        query = query.First(&user)

        users = append(users, &user)
    }

    return users, nil
}

返回结果:

{
    "code": 0,
    "message": "success",
    "data": [
        {
            "id": 38,
            "name": "测试修改",
            "phone": "13137284666",
            "cid": null,
            "is_root": 0,
            "created_at": "2020-01-09T16:51:56+08:00",
            "cids": [],
            "roles": [
                {
                    "id": 2,
                    "name": "普通用户",
                    "created_at": "2019-10-25T16:38:23+08:00",
                    "updated_at": "2019-10-25T16:38:23+08:00",
                    "users": null,
                    "permissions": null
                }
            ],
            "children": null,
            "parent": {
                "id": 29,
                "name": "用户1",
                "phone": "13437284998",
                "cid": null,
                "is_root": 1,
                "created_at": "2019-10-29T09:59:16+08:00",
                "cids": null,
                "roles": null,
                "children": null,
                "parent": null
            }
        },
        {
            "id": 35,
            "name": "kll",
            "phone": "17354306026",
            "cid": null,
            "is_root": 1,
            "created_at": "2020-01-08T15:17:40+08:00",
            "cids": [
                {
                    "id": 47,
                    "cid": "10030",
                    "user_id": 0,
                    "agent_name": "周万林",
                    "province": "湖北省",
                    "city": "荆州市",
                    "promoter": "刘超俊",
                    "remark": "",
                    "created_at": "2019-10-29T12:21:17+08:00",
                    "updated_at": "2019-10-29T12:21:17+08:00",
                    "users": null,
                    "products": null
                },
                {
                    "id": 48,
                    "cid": "10031",
                    "user_id": 0,
                    "agent_name": "XX欢",
                    "province": "江苏省",
                    "city": "苏州市",
                    "promoter": "XX钰",
                    "remark": "",
                    "created_at": "2019-10-29T12:22:02+08:00",
                    "updated_at": "2019-11-01T14:33:43+08:00",
                    "users": null,
                    "products": null
                }
            ],
            "roles": [
                {
                    "id": 1,
                    "name": "超级管理员",
                    "created_at": "2019-10-25T16:38:23+08:00",
                    "updated_at": "2019-10-25T16:38:23+08:00",
                    "users": null,
                    "permissions": null
                }
            ],
            "children": [],
            "parent": null
        },
        {
            "id": 34,
            "name": "wew",
            "phone": "wew",
            "cid": null,
            "is_root": 1,
            "created_at": "2020-01-03T16:27:18+08:00",
            "cids": [
                {
                    "id": 79,
                    "cid": "ABCD1234",
                    "user_id": 0,
                    "agent_name": "hwt2",
                    "province": "XXX",
                    "city": "XX市",
                    "promoter": "XX涛",
                    "remark": "2",
                    "created_at": "2020-04-17T14:39:53+08:00",
                    "updated_at": "2020-04-17T14:39:53+08:00",
                    "users": null,
                    "products": null
                },
                {
                    "id": 46,
                    "cid": "10029",
                    "user_id": 0,
                    "agent_name": "侯蒙",
                    "province": "安徽省",
                    "city": "阜阳市",
                    "promoter": "张雅静",
                    "remark": "",
                    "created_at": "2019-10-29T12:20:43+08:00",
                    "updated_at": "2019-10-29T12:20:43+08:00",
                    "users": null,
                    "products": null
                }
            ],
            "roles": [
                {
                    "id": 3,
                    "name": "数据查看",
                    "created_at": "2019-10-25T16:48:48+08:00",
                    "updated_at": "2019-10-25T16:48:48+08:00",
                    "users": null,
                    "permissions": null
                },
                {
                    "id": 11,
                    "name": "代理商",
                    "created_at": "2020-01-09T17:23:53+08:00",
                    "updated_at": "2020-01-09T17:23:53+08:00",
                    "users": null,
                    "permissions": null
                }
            ],
            "children": [
                {
                    "id": 61,
                    "name": "1232",
                    "phone": "123",
                    "cid": "1000111",
                    "is_root": 0,
                    "created_at": "2020-01-18T18:45:12+08:00",
                    "cids": null,
                    "roles": null,
                    "children": null,
                    "parent": null
                },
                {
                    "id": 66,
                    "name": "33",
                    "phone": "13554204137",
                    "cid": null,
                    "is_root": 0,
                    "created_at": "2020-04-17T12:10:05+08:00",
                    "cids": null,
                    "roles": null,
                    "children": null,
                    "parent": null
                }
            ],
            "parent": null
        }
    ],
    "total": 40,
    "per_page": 3,
    "current_page": 10,
    "total_page": 14
}

返回的结果隐藏了 password 等字段
users 多对多 roles
users 多对多 cids
users 一对多 自己的 children
users 多对一 自己的 parent

勿笑,新手参照gorm写的,总觉得那个for里面被我写了sql有点不好,求帮优化下

讨论数量: 7
taadis

10条分页数据查询出来后, 根据id去查询对应 roles/cids, 再在 for 循环中匹配关联的数据, 写法上会分离点, 但是能避免 for 循环内的循环数据库操作.

4年前 评论

@taadis 不是很明白,我去看看日志打印了几条数据先

4年前 评论
taadis

file

4年前 评论

@taadis 在for之前拿的到每条user的id吗?感觉拿不到吧

4年前 评论
taadis

...你 for 之前查询出来的 rows 是啥数据?

4年前 评论

@taadis rows也得遍历才能拿到具体的单个id吧,总感觉你说的那样不行,下周我试试你说的

4年前 评论
taadis 4年前

单一职责原则,分页应该只包含分页逻辑,将关联查询单独分离成方法,接受者为*user,返回[]user, 降低耦合,方便复用

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!