使用 orm 实现增删改查 - beego 框架使用笔记

BaconHilary 发布于29天前
0 条问题

beego ORM 是一个强大的 Go 语言 ORM 框架,目前该框架已支持 MySQL、PostgreSQL、Sqlite3 数据库驱动。

安装 ORM

go get github.com/astaxie/beego/orm
复制代码

初始化

创建项目

使用 bee 工具的安装 api 命令 bee api apiproject 创建 apiproject 项目,具体使用方法查看 beego api 命令

模型关系

# 外键始终在子表上
# 一个用户对应一个简介;一个简介对应一个用户;
one2one:User(子表) -> Profile(主表);one2one:Profile -> User 
复制代码

结构体

type User struct {
    Id          int         `json:"id"`
    Username    string      `json:"username"`
    Password    string      `json:"password"`
    Profile     *Profile    `orm:"rel(one)" json:"profile"` // OneToOne relation
}

type Profile struct {
    Id          int         `json:"id"`
    Gender      int         `json:"gender"`
    Age         int         `json:"age"`
    Address     string      `json:"address"`
    Email       string      `json:"email"`
    User        *User       `orm:"reverse(one)" json:"-"` // 设置一对一反向关系(可选)
}
复制代码
使用标签`orm:"column(id)`对属性进行标注,用于解析。
`orm:"rel(one)"` 表示one2one
`orm:"reverse(one)"` `orm:"reverse(one)"`  标注反向关系
复制代码

database 信息

注册 model:

orm.RegisterModel(new(User), new(Profile))
复制代码

自定义表名:

func (u *User) TableName() string {
	return "users"
}

func (u *Profile) TableName() string {
	return "users_profiles"
}
复制代码

自动建表:

orm.RunSyncdb("default", false, true)
复制代码

数据表结构:

mysql> show tables;
+-------------------+
| Tables_in_play_db |
+-------------------+
| users             |
| users_profiles    |
+-------------------+
2 rows in set (0.01 sec)

mysql> desc users;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int(11)      | NO   | PRI | NULL    | auto_increment |
| username   | varchar(255) | NO   |     |         |                |
| password   | varchar(255) | NO   |     |         |                |
| profile_id | int(11)      | NO   | UNI | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
4 rows in set (0.02 sec)

mysql> desc users_profiles;
+---------+--------------+------+-----+---------+----------------+
| Field   | Type         | Null | Key | Default | Extra          |
+---------+--------------+------+-----+---------+----------------+
| id      | int(11)      | NO   | PRI | NULL    | auto_increment |
| gender  | int(11)      | YES  |     | 0       |                |
| age     | int(11)      | YES  |     | 0       |                |
| address | varchar(255) | YES  |     |         |                |
| email   | varchar(255) | YES  |     |         |                |
+---------+--------------+------+-----+---------+----------------+
5 rows in set (0.01 sec)
复制代码

功能实现

项目参数配置

/apiproject/conf/app.conf

appname = apiproject
httpport = 8090
runmode = dev
autorender = false
copyrequestbody = true
EnableDocs = true
sqlconn = root:123456@/play_db?charset=utf8
复制代码

通用 utils

分页:

/apiproject/utils/page.go

package utils

var (
	PageSize int = 10
)

type Page struct {
	Page     	int             `json:"page"`
	PageSize	int             `json:"pageSize"`
	TotalPage	int             `json:"totalPage"`
	TotalCount	int             `json:"totalCount"`
	FirstPage	bool            `json:"firstPage"`
	LastPage	bool            `json:"lastPage"`
	List		interface{}     `json:"list"`
}

func Pagination(count int, page int, pageSize int, list interface{}) Page {
	tp := count / pageSize
	if count%pageSize > 0 {
		tp = count/pageSize + 1
	}
	return Page{Page: page, PageSize: pageSize, TotalPage: tp, TotalCount: count, FirstPage: page == 1, LastPage: page == tp, List: list}
}
复制代码

main 入口

/apiproject/main.go

package main

import (
	_ "apiproject/routers"
	"github.com/astaxie/beego/orm"
	"github.com/astaxie/beego"
	_ "github.com/go-sql-driver/mysql"
)

func init() {
	// 参数1   driverName
	// 参数2   数据库类型
	// 这个用来设置 driverName 对应的数据库类型
	// mysql / sqlite3 / postgres 这三种是默认已经注册过的,所以可以无需设置
	// orm.RegisterDriver("mysql", orm.DRMySQL)

	// ORM 必须注册一个别名为 default 的数据库,作为默认使用。
	// 参数1		数据库的别名,用来在 ORM 中切换数据库使用
	// 参数2		driverName
	// 参数3		对应的链接字符串
	orm.RegisterDataBase("default", "mysql", beego.AppConfig.String("sqlconn"))
}

func main() {
	if beego.BConfig.RunMode == "dev" {
		beego.BConfig.WebConfig.DirectoryIndex = true
		beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
	}

	// 开启 orm 调试模式:开发过程中建议打开,release时需要关闭
	orm.Debug = true

	beego.Run()
}
复制代码

路由实现

RESTful Controller 路由,初始化 namespace:

/apiproject/routers/router.go

// @APIVersion 1.0.0
// @Title apiproject API
// @License Apache 2.0
package routers

import (
	"apiproject/controllers"

	"github.com/astaxie/beego"
)

func init() {
	ns := beego.NewNamespace("/v1",
		beego.NSNamespace("/object",
			beego.NSInclude(
				&controllers.ObjectController{},
			),
		),
		beego.NSNamespace("/user",
			beego.NSInclude(
				&controllers.UserController{},
			),
		),
	)
	beego.AddNamespace(ns)
}
复制代码

/apiproject/routers/commentsRouter_controllers.go

package routers

import (
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/context/param"
)

func init() {

    beego.GlobalControllerRouter["apiproject/controllers:UserController"] = append(beego.GlobalControllerRouter["apiproject/controllers:UserController"],
        beego.ControllerComments{
            Method: "Post",
            Router: `/`,
            AllowHTTPMethods: []string{"post"},
            MethodParams: param.Make(),
            Filters: nil,
            Params: nil})

    beego.GlobalControllerRouter["apiproject/controllers:UserController"] = append(beego.GlobalControllerRouter["apiproject/controllers:UserController"],
        beego.ControllerComments{
            Method: "GetAll",
            Router: `/`,
            AllowHTTPMethods: []string{"get"},
            MethodParams: param.Make(),
            Filters: nil,
            Params: nil})

    beego.GlobalControllerRouter["apiproject/controllers:UserController"] = append(beego.GlobalControllerRouter["apiproject/controllers:UserController"],
        beego.ControllerComments{
            Method: "Get",
            Router: `/:uid`,
            AllowHTTPMethods: []string{"get"},
            MethodParams: param.Make(),
            Filters: nil,
            Params: nil})

    beego.GlobalControllerRouter["apiproject/controllers:UserController"] = append(beego.GlobalControllerRouter["apiproject/controllers:UserController"],
        beego.ControllerComments{
            Method: "Put",
            Router: `/:uid`,
            AllowHTTPMethods: []string{"put"},
            MethodParams: param.Make(),
            Filters: nil,
            Params: nil})

    beego.GlobalControllerRouter["apiproject/controllers:UserController"] = append(beego.GlobalControllerRouter["apiproject/controllers:UserController"],
        beego.ControllerComments{
            Method: "Delete",
            Router: `/:uid`,
            AllowHTTPMethods: []string{"delete"},
            MethodParams: param.Make(),
            Filters: nil,
            Params: nil})

}
复制代码

controller 实现

通用 controller base:

/apiproject/controllers/base.go

package controllers

import (
	"github.com/astaxie/beego"
)

type BaseController struct {
	beego.Controller
}

// Response 结构体
type Response struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data"`
}

// Error Response 结构体
type ErrResponse struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
}
复制代码

自定义错误提示码:

/apiproject/controllers/code.go

package controllers

var (
	// Common errors
	SUCCESS             = &Errno{Code: 0, Message: "成功"}
	InternalServerError = &Errno{Code: 10001, Message: "内部服务错误"}
	ErrBind             = &Errno{Code: 10002, Message: "参数错误"}

	ErrDatabase       = &Errno{Code: 20001, Message: "数据库错误"}
	ErrToken          = &Errno{Code: 20002, Message: "签发令牌出错"}
	ErrNoPermission   = &Errno{Code: 20003, Message: "无权限"}

	// user errors
	ErrUserNotFound       = &Errno{Code: 20101, Message: "用户未注册"}
	ErrUserExist          = &Errno{Code: 20102, Message: "用户已存在"}
)
复制代码

通用错误处理:

/apiproject/controllers/errno.go

package controllers

import "fmt"

type Errno struct {
	Code    int
	Message string
}

func (err Errno) Error() string {
	return err.Message
}

// Err represents an error
type Err struct {
	Code    int
	Message string
	Err     error
}

func New(errno *Errno, err error) *Err {
	return &Err{Code: errno.Code, Message: errno.Message, Err: err}
}

func (err *Err) Add(message string) error {
	err.Message += " " + message
	return err
}

func (err *Err) Addf(format string, args ...interface{}) error {
	err.Message += " " + fmt.Sprintf(format, args...)
	return err
}

func (err *Err) Error() string {
	return fmt.Sprintf("Err - code: %d, message: %s, error: %s", err.Code, err.Message, err.Err)
}

func IsErrUserNotFound(err error) bool {
	code, _ := DecodeErr(err)
	return code == ErrUserNotFound.Code
}

func DecodeErr(err error) (int, string) {
	if err == nil {
		return SUCCESS.Code, SUCCESS.Message
	}

	switch typed := err.(type) {
	case *Err:
		return typed.Code, typed.Message
	case *Errno:
		return typed.Code, typed.Message
	default:
	}

	return InternalServerError.Code, err.Error()
}
复制代码

用户 controller 模块:

/apiproject/controllers/user.go

package controllers

import (
	"apiproject/models"
	"apiproject/utils"
	"encoding/json"
	"strconv"
)

// Operations about Users
type UserController struct {
	BaseController
}

// @Title CreateUser
// @Description create users
// @Param	body		body 	models.User	true		"body for user content"
// @Success 200 {int} models.User.Id
// @Failure 403 body is empty
// @router / [post]
func (u *UserController) Post() {
	var user models.User
	_ = json.Unmarshal(u.Ctx.Input.RequestBody, &user)
	uid, _ := models.AddUser(user)
	u.Data["json"] = map[string]int64{"uid": uid}
	u.ServeJSON()
}

// @Title GetAll
// @Description get all Users
// @Success 200 {object} models.User
// @router / [get]
func (u *UserController) GetAll() {
	currentPage, _ := strconv.Atoi(u.Ctx.Input.Query("page"))
	if currentPage == 0 {
		currentPage = 1
	}
	pageSize := utils.PageSize
	d , err:= models.GetAllUsers(currentPage,pageSize)
	code, message := DecodeErr(err)

	if err != nil {
		u.Data["json"] = ErrResponse{code, message}
	} else {
		u.Data["json"] = Response{code, message, d}
	}
	u.ServeJSON()
}

// @Title Get
// @Description get user by uid
// @Param	uid		path 	string	true		"The key for staticblock"
// @Success 200 {object} models.User
// @Failure 403 :uid is empty
// @router /:uid [get]
func (u *UserController) Get() {
	uid, _ := u.GetInt(":uid")
	if uid > 0 {
		user, err := models.GetUser(uid)
		code, message := DecodeErr(err)
		if err != nil {
			u.Data["json"] = ErrResponse{code, message}
		} else {
			u.Data["json"] = Response{code, message, user}
		}
	}
	u.ServeJSON()
}

// @Title Update
// @Description update the user
// @Param	uid		path 	string	true		"The uid you want to update"
// @Param	body		body 	models.User	true		"body for user content"
// @Success 200 {object} models.User
// @Failure 403 :uid is not int
// @router /:uid [put]
func (u *UserController) Put() {
	uid, _ := u.GetInt(":uid")
	if uid > 0 {
		var user models.User
		_ = json.Unmarshal(u.Ctx.Input.RequestBody, &user)
		uu, err := models.UpdateUser(uid, &user)
		code, message := DecodeErr(err)
		if err != nil {
			u.Data["json"] = ErrResponse{code, message}
		} else {
			u.Data["json"] = Response{code, message, uu}
		}
	}
	u.ServeJSON()
}

// @Title Delete
// @Description delete the user
// @Param	uid		path 	string	true		"The uid you want to delete"
// @Success 200 {string} delete success!
// @Failure 403 uid is empty
// @router /:uid [delete]
func (u *UserController) Delete() {
	uid, _ := u.GetInt(":uid")
	b, err := models.DeleteUser(uid)
	code, message := DecodeErr(err)
	if err != nil {
		u.Data["json"] = ErrResponse{code, message}
	} else {
		u.Data["json"] = Response{code, message, b}
	}
	u.ServeJSON()
}
复制代码

model 实现

用户 model 模块,orm 实现 增删改查:

/apiproject/models/user.go

package models

import (
	"apiproject/utils"
	"errors"
	"github.com/astaxie/beego/orm"
	"strconv"
)

type User struct {
    Id          int         `json:"id"`
    Username    string      `json:"username"`
    Password    string      `json:"password"`
    Profile     *Profile    `orm:"rel(one)" json:"profile"` // OneToOne relation
}

type Profile struct {
    Id          int         `json:"id"`
    Gender      int         `json:"gender"`
    Age         int         `json:"age"`
    Address     string      `json:"address"`
    Email       string      `json:"email"`
    User        *User       `orm:"reverse(one)" json:"-"` // 设置一对一反向关系(可选)
}

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

func (u *Profile) TableName() string {
	return "users_profiles"
}

// 新增用户
func AddUser(u User) (id int64, err error) {
	// one2one 插入
	// 创建一个 ormer 对象
	o := orm.NewOrm()

	// 开启事务
	err = o.Begin()

	// 插入主表
	profile := Profile{
		Gender: u.Profile.Gender,
		Age: u.Profile.Age,
		Address: u.Profile.Address,
		Email: u.Profile.Email}
	id, err = o.Insert(&profile)
	if err != nil {
		// 回滚事务
		err = o.Rollback()
	}

	// 插入子表
	user := User{
		Username: u.Username,
		Password: u.Password,
		Profile: &Profile{Id: int(id)}}
	_, err = o.Insert(&user)
	if err != nil {
		// 回滚事务
		err = o.Rollback()
	}

	// 提交事务
	err = o.Commit()
	return id, err
}

// 查询指定用户
func GetUser(uid int) (u *User, err error) {
	o := orm.NewOrm()

	user := &User{Id: uid}
	err = o.Read(user)

	// 已经取得了 Users 对象,查询 UserProfiles
	if user.Profile != nil {
		err = o.Read(user.Profile)
	}

	return user, err
}

// 分页查询用户
func GetAllUsers(p int, size int) (u utils.Page, err error) {
	o := orm.NewOrm()
	user := new(User)
	var users []User
	qs := o.QueryTable(user)
	count, _ := qs.Limit(-1).Count()
	_, err = qs.RelatedSel().Limit(size).Offset((p - 1) * size).All(&users)
	for _, u := range users {
		if u.Profile != nil {
			err = o.Read(u.Profile)
		}
	}
	c, _ := strconv.Atoi(strconv.FormatInt(count, 10))
	return utils.Pagination(c, p, size, users), err
}

// 更新指定用户
func UpdateUser(uid int, uu *User) (a *User, err error) {
	o := orm.NewOrm()
	user := User{Id: uid}
	profile := Profile{Id: uid}

	if o.Read(&user) == nil {

		if uu.Username != "" {
			user.Username = uu.Username
		}
		if uu.Password != "" {
			user.Password = uu.Password
		}

		if o.Read(&profile) == nil {

			if uu.Profile.Age > 0 {
				profile.Age = uu.Profile.Age
			}
			if uu.Profile.Address != "" {
				profile.Address = uu.Profile.Address
			}
			if uu.Profile.Gender == 0 || uu.Profile.Gender == 1 {
				profile.Gender = uu.Profile.Gender
			}
			if uu.Profile.Email != "" {
				profile.Email = uu.Profile.Email
			}
		}

		user.Profile = &profile

		// 开启事务
		err = o.Begin()

		if _, err := o.Update(&user); err != nil {
			return nil, errors.New("修改失败")
		}

		if _, err := o.Update(&profile); err != nil {
			return nil, errors.New("修改失败")
		}
		if err != nil {
			err = o.Rollback()
		} else {
			err = o.Commit()
		}
		return &user, nil
	}

	return nil, err
}

// 删除指定用户
func DeleteUser(uid int) (b bool, err error) {
	// one2one 删除
	// 创建一个 ormer 对象
	o := orm.NewOrm()

	// 开启事务
	err = o.Begin()

	// 删除主表
	profile := Profile{Id: uid}
	_, err = o.Delete(&profile)
	if err != nil {
		// 回滚事务
		err = o.Rollback()
	}

	// 删除子表
	user := User{Id: uid}
	_, err = o.Delete(&user)
	if err != nil {
		// 回滚事务
		err = o.Rollback()
	}

	// 提交事务
	err = o.Commit()
	return b, err
}

// 注册 model
func init(){
	orm.RegisterModel(new(User), new(Profile))
}
复制代码

查看原文: 使用 orm 实现增删改查 - beego 框架使用笔记

  • smallsnake
  • crazygorilla
  • smallduck
需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。