GoFrame ORM 使用实践分享

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

前言

本月会持续更新Go语言相关的文章,尤其是GoFrame,感兴趣的同学可以关注我,结伴而行。

同时会沉淀总结一下:《中台开发实践》、《私有化部署实践》、《深入理解goroutine及使用实践》、《如何在开发过程中把GO语言的价值体现出来》。

立志沉淀一些质量高的内容出来。

今天这篇把我使用GoFrame ORM的过程中认为有价值、可能踩坑、比较好的实践等相关的知识点分享出来。

值类型和指针类型

初学go的时候一直在纠结值类型和指针类型,后来在用的过程中发现大可不必纠结。

指针类型的优势就是节省内存空间,多个变量指向同一个内存地址,一荣俱荣,一个修改,处处修改。

而值类型可以简单理解为:避免这种一处修改处处修改的问题,有些场景下我们不能单纯的考虑性能,不能单纯地只考虑复用

在GoFrame中也鼓励我们使用指针类型,举个栗子:

使用Scan将查询结果转换成struct对象

Scan支持将查询结果转换为一个struct对象,查询结果应当是特定的一条记录,并且pointer参数应当为struct对象的指针地址(*struct或者**struct),使用方式例如:

type User struct {
    Id         int
    Passport   string
    Password   string
    NickName   string
    CreateTime *gtime.Time
}
user := User{}
g.Model("user").Where("id", 1).Scan(&user)
复制代码

或者

var user = User{}
g.Model("user").Where("id", 1).Scan(&user)
复制代码

前两种方式都是预先初始化对象(提前分配内存)

推荐的方式如下,这种方式只有在查询到数据的时候才会执行初始化及内存分配:

var user *User
g.Model("user").Where("id", 1).Scan(&user)
复制代码

注意在用法上的区别,特别是传递参数类型的差别(前两种方式传递的参数类型是*User,这里传递的参数类型其实是**User)。

插入数据

InsertIgnore

这个函数需要重点和大家说一下,因为我之前有Laravel的使用经验,Laravel中的InsertIgnore是配合唯一索引使用,意思是如果存在唯一主键或者唯一索引就忽略掉,不重复插入。

在GoFrame中是相反的:

GoFrame中默认的insert函数,就会根据唯一索引(或主键)执行,如果有存在的数据返回失败,不重复插入。

而GoFrame中的InsertIgnore是忽略错误继续插入,而不是存在就不插入。

大家在使用中要注意。

灵活执行SQL

我们要拼接自定义的sql参数怎么办法呢?

gdb.Raw()

示例如下:

OnDuplicate(g.Map{
    "nickname": gdb.Raw("CONCAT('name_', VALUES(`nickname`))"),
})
复制代码

gdb.Raw() 中的参数将作为sql执行的语句,不会自动转换成字符串类型,也不会作为预处理参数。

示例如下:

// INSERT INTO `user`(`id`,`passport`,`password`,`nickname`,`create_time`) VALUES(id+2,'80','123456','wzy',now())
g.Model("user").Data(g.Map{
	"id":          gdb.Raw("id+2"),
	"passport":    "80",
	"password":    "123456",
	"nickname":    "wzy",
	"create_time": gdb.Raw("now()"),
}).Insert()
复制代码

链式安全

我们首先要有这个概念:什么是链式安全?

其实很简单:链式安全就是操作model模型时不会改变当前model对象,模型属性修改/条件叠加需要使用赋值来操作。

链式非安全或者非链式安全就是:操作model模型时会改变当前model对象的属性。

在GoFrame开发过程中,强烈建议使用gf gen dao生成的model和dao文件!!!

通过gf gen dao生成的model和dao文件默认是链式安全的。

举例如下:

func NewGomeStockDao() *GomeStockDao {
   return &GomeStockDao{
      M:     g.DB("default").Model("gome_stock").Safe(), //注意看这里
      DB:    g.DB("default"),
      Table: "gome_stock",
      Columns: gomeStockColumns{
         Id:            "id",
         MchWhseCode:   "mch_whse_code",
         MchWhseName:   "mch_whse_name",
         IsNationWide:  "is_nation_wide",
         Status:        "status",
         LastUpateTime: "last_upate_time",
      },
   }
}
复制代码

链式安全时我们如何叠加条件改变呢?

答案就是:通过赋值。

链式安全时通过 m = m.xxx 方式赋值实现链式调用

举例如下:

m := user.Where("status IN(?)", g.Slice{1,2,3})
if vip {
    // 查询条件通过赋值叠加
    m = m.And("money>=?", 1000000)
} else {
    // 查询条件通过赋值叠加
    m = m.And("money<?",  1000000)
}
//  vip: SELECT * FROM user WHERE status IN(1,2,3) AND money >= 1000000
// !vip: SELECT * FROM user WHERE status IN(1,2,3) AND money < 1000000
r, err := m.All()
//  vip: SELECT COUNT(1) FROM user WHERE status IN(1,2,3) AND money >= 1000000
// !vip: SELECT COUNT(1) FROM user WHERE status IN(1,2,3) AND money < 1000000
n, err := m.Count()
复制代码

总结

碰到好的东西就忍不住分享,我现在可以说是Go语言的忠实拥趸。

对GO感兴趣的朋友可以查看我之前写的文章,了解一下Go的魅力:

Go语言为什么值得学习?

我的PHP转Go之旅

回顾一下我的Go学习之旅

非常适合PHP和Java转Go学习的框架:GoFrame

欢迎大家关注我的Go语言学习专栏,我会持续更新在Go学习和使用过程中的干货分享。

Go语言学习专栏

最后

感谢阅读,欢迎大家三连:点赞、收藏、投币(关注)!!!

8e95dac1fd0b2b1ff51c08757667c47a.gif

猜你喜欢

转载自juejin.im/post/7082278651681013773
Orm