- Created by 郭强, last modified by Wankko Ree on Aug 04, 2023
模型创建
Model
Model
方法用于创建基于数据表的Model
对象。常见的,也可以使用g
对象管理模块中的Model
方法在默认的数据库配置上创建Model
对象。
使用示例:
g.Model("user") // 或者 g.DB().Model("user")
此外,在某些场景下,我们也可以通过DB
方法切换当前模型的数据库对象,例如:
m := g.Model("user") m = m.DB(g.DB("order"))
其效果与以下操作是一样的:
m := g.DB("user").Model("user")
Raw
Raw
方法用于创建一个基于原始SQL
语句的Model
对象。也可以使用g
对象管理模块中的ModelRaw
方法通过给定的SQL
语句在默认的数据库配置上创建Model
对象。
s := "SELECT * FROM `user`" m, _ := g.ModelRaw(s).WhereLT("age", 18).Limit(10).OrderAsc("id").All() // SELECT * FROM `user` WHERE `age`<18 ORDER BY `id` ASC LIMIT 10
s := "SELECT * FROM `user` WHERE `status` IN(?)" m, _ := g.ModelRaw(s, g.Slice{1,2,3}).WhereLT("age", 18).Limit(10).OrderAsc("id").All() // SELECT * FROM `user` WHERE `status` IN(1,2,3) AND `age`<18 ORDER BY `id` ASC LIMIT 10
链式安全
链式安全
只是模型操作的两种方式区别:一种会修改当前model
对象(不安全,默认),一种不会(安全)但是模型属性修改/条件叠加需要使用赋值操作,仅此而已。
默认情况
在默认情况下,gdb
是非链式安全
的,也就是说链式操作的每一个方法都将对当前操作的Model
属性进行修改,因此该Model
对象不可以重复使用。例如,当存在多个分开查询的条件时,我们可以这么来使用Model
对象:
user := g.Model("user") user.Where("status", g.Slice{1,2,3}) if vip { // 查询条件自动叠加,修改当前模型对象 user.Where("money>=?", 1000000) } else { // 查询条件自动叠加,修改当前模型对象 user.Where("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 := user.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 := user.Count()
可以看到,如果是分开执行链式操作,链式的每一个操作都会修改已有的Model
对象,查询条件会自动叠加,因此user
对象不可重复使用,否则条件会不停叠加。并且在这种使用方式中,每次我们需要操作user
用户表,都得使用g.DB().Table("user")
这样的语法创建一个新的user
模型对象,相对来说会比较繁琐。
默认情况下,基于性能以及GC优化考虑,模型对象为非链式安全
,防止产生过多的临时模型对象。
不过需要注意的是,如果使用的是cli工具gen dao
生成的dao
,如user := dao.User.Ctx(ctx)
,此时获取到的user
Model
对象默认是链式安全的(已自动调用过.Safe()
)。
Clone
方法
此外,我们也可以手动调动Clone
方法克隆当前模型,创建一个新的模型来实现链式安全,由于是新的模型对象,因此并不担心会修改已有的模型对象的问题。例如:
// 定义一个用户模型单例 user := g.Model("user")
// 克隆一个新的用户模型 m := user.Clone() m.Where("status", g.Slice{1,2,3}) if vip { m.Where("money>=?", 1000000) } else { m.Where("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()
Safe
方法
当然,我们可以通过Safe
方法设置当前模型为链式安全
的对象,后续的每一个链式操作都将返回一个新的Model
对象,该Model
对象可重复使用。但需要特别注意的是,模型属性的修改,或者操作条件的叠加,需要通过变量赋值的方式(m = m.xxx
)覆盖原有的模型对象来实现。例如:
// 定义一个用户模型单例 user := g.Model("user").Safe()
m := user.Where("status", g.Slice{1,2,3}) if vip { // 查询条件通过赋值叠加 m = m.Where("money>=?", 1000000) } else { // 查询条件通过赋值叠加 m = m.Where("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()
可以看到,示例中的用户模型单例对象user
可以重复使用,而不用担心被“污染”的问题。在这种链式安全的方式下,我们可以创建一个用户单例对象user
,并且可以重复使用到后续的各种查询中。但是存在多个查询条件时,条件的叠加需要通过模型赋值操作(m = m.xxx
)来实现。
使用Safe
方法标记之后,每一个链式操作都将会创建一个新的临时模型对象(内部自动使用Clone
实现模型克隆),从而实现链式安全。这种使用方式在模型操作中比较常见。
- No labels
4 Comments
扶程星云
请问,如果我用m.Count()获得总数后,然后场景需要重新给条件,是需要重新定义一个模型单例吗?有没有清除查询条件的命令?
david
文档中已经说的很清楚了,构造好查询对象之后,Clone一个走Count(),如果Count()的返回值大于0,再用原来的查询对象走select即可完成手动分页查询了。
趴哥 KingFly
秒啊
yidashi
这个safe比较鸡肋,我说用框架生成的dao代码怎么不能链式操作,原来是自己加了safe.....