- Created by 郭强, last modified on Sep 01, 2021
Fields/FieldsEx
字段过滤
Fields
用于指定需要操作的表字段,包括查询字段、写入字段、更新字段等过滤;FieldsEx
用于例外的字段指定,可用于查询字段、写入字段、更新字段等过滤;
Fields
示例
- 假如
user
表有4个字段uid
,nickname
,passport
,password
。 查询字段过滤
// SELECT `uid`,`nickname` FROM `user` ORDER BY `uid` asc db.Table("user").Fields("uid, nickname").Order("uid asc").All()
写入字段过滤
m := g.Map{ "uid" : 10000, "nickname" : "John Guo", "passport" : "john", "password" : "123456", } db.Table(table).Fields("nickname,passport,password").Data(m).Insert() // INSERT INTO `user`(`nickname`,`passport`,`password`) VALUES('John Guo','john','123456')
FieldsEx
示例
- 假如
user
表有4个字段uid
,nickname
,passport
,password
。 查询字段排除
// SELECT `uid`,`nickname` FROM `user` db.Table("user").FieldsEx("passport, password").All()
写入字段排除
m := g.Map{ "uid" : 10000, "nickname" : "John Guo", "passport" : "john", "password" : "123456", } db.Table(table).FieldsEx("uid").Data(m).Insert() // INSERT INTO `user`(`nickname`,`passport`,`password`) VALUES('John Guo','john','123456')
OmitEmpty
空值过滤
当 map
/struct
中存在空值如 nil
,""
,0
时,默认情况下,gdb
将会将其当做正常的输入参数,因此这些参数也会被更新到数据表。OmitEmpty
特性可以在将数据写入到数据库之前过滤空值数据的字段。
相关方法:
func (m *Model) OmitEmpty() *Model func (m *Model) OmitEmptyWhere() *Model func (m *Model) OmitEmptyData() *Model
OmitEmpty
方法会同时过滤Where
及Data
中的空值数据,而通过OmitEmptyWhere/OmitEmptyData
方法可以执行特定的字段过滤。
写入/更新操作
空值会影响于写入/更新操作方法,如Insert
, Replace
, Update
, Save
操作。如以下操作(以map
为例,struct
同理):
// UPDATE `user` SET `name`='john',update_time=null WHERE `id`=1 db.Table("user").Data(g.Map{ "name" : "john", "update_time" : nil, }).Where("id", 1).Update()
针对空值情况,我们可以通过OmitEmpty
方法来过滤掉这些空值。例如,以上示例可以修改为:
// UPDATE `user` SET `name`='john' WHERE `id`=1 db.Table("user").OmitEmpty().Data(g.Map{ "name" : "john", "update_time" : nil, }).Where("id", 1).Update()
对于struct
数据参数,我们也可以进行空值过滤。操作示例:
type User struct { Id int `orm:"id"` Passport string `orm:"passport"` Password string `orm:"password"` NickName string `orm:"nickname"` CreateTime string `orm:"create_time"` UpdateTime string `orm:"update_time"` } user := User{ Id : 1, NickName : "john", UpdateTime: gtime.Now().String(), } db.Table("user").OmitEmpty().Data(user).Insert() // INSERT INTO `user`(`id`,`nickname`,`update_time`) VALUES(1,'john','2019-10-01 12:00:00')
注意哟,批量写入/更新操作中OmitEmpty
方法将会失效,因为在批量操作中,必须保证每个写入记录的字段是统一的。
关于omitempty
标签与OmitEmpty
方法:
- 针对于
struct
的空值过滤大家会想到omitempty
的标签。该标签常用于json
转换的空值过滤,也在某一些第三方的ORM
库中用作struct
到数据表字段的空值过滤,即当属性为空值时不做转换。 omitempty
标签与OmitEmpty
方法所达到的效果是一样的。在ORM
操作中,我们不建议对struct
使用omitempty
的标签来控制字段的空值过滤,而建议使用OmitEmpty
方法来做控制。因为该标签一旦加上之后便绑定到了struct
上,没有办法做灵活控制;而通过OmitEmpty
方法使得开发者可以选择性地、根据业务场景对struct
做空值过滤,操作更加灵活。
数据查询操作
空值也会影响数据查询操作,主要是影响where
条件参数。我们可以通过OmitEmpty
方法过滤条件参数中的空值。
使用示例:
// SELECT * FROM `user` WHERE `passport`='john' LIMIT 1 r, err := db.Table("user").Where(g.Map{ "nickname" : "", "passport" : "john", }).OmitEmpty().One()
type User struct { Id int `orm:"id"` Passport string `orm:"passport"` Password string `orm:"password"` NickName string `orm:"nickname"` CreateTime string `orm:"create_time"` UpdateTime string `orm:"update_time"` } user := User{ Passport : "john", } r, err := db.Table("user").OmitEmpty().Where(user).One() // SELECT * FROM `user` WHERE `passport`='john' LIMIT 1
OmitNil
空值过滤
当 map
/struct
中存在空值如 nil
时,默认情况下,gdb
将会将其当做正常的输入参数,因此这些参数也会被更新到数据表。OmitNil
特性可以在将数据写入到数据库之前过滤空值数据的字段。与OmitEmpty
特性的区别在于,OmitNil
只会过滤值为nil
的空值字段,其他空值如""
,0
并不会被过滤。
相关方法:
func (m *Model) OmitNil() *Model func (m *Model) OmitNilWhere() *Model func (m *Model) OmitNilData() *Model
OmitEmpty
方法会同时过滤Where
及Data
中的空值数据,而通过OmitEmptyWhere/OmitEmptyData
方法可以执行特定的字段过滤。
Filter
字段过滤(已内置)
gdb
可以自动同步数据表结构到程序缓存中(缓存不过期,直至程序重启/重新部署),并且可以过滤提交参数中不符合表结构的数据项,该特性可以使用Filter
方法实现。常用于新增/删除操作中输入map/struct/[]map/[]string
参数类型的场景。
使用示例,假如user
表有4个字段uid
, nickname
, passport
, password
:
r, err := db.Table("user").Filter().Data(g.Map{ "id" : 1, "uid" : 1, "passport" : "john", "password" : "123456", }).Insert() // INSERT INTO user(uid,passport,password) VALUES(1, "john", "123456")
其中id
为不存在的字段,在写入数据时将会被过滤掉,不至于被构造成写入SQL中产生执行错误。
数据库没有设计为Data
方法做自动过滤,而是需要开发者调用Filter
方法来手动指定过滤,目的是友好地提醒开发者可能误写/传递错误了字段名称。如果强制性的自动过滤可能会引起难以预料的业务逻辑异常,例如,由于字段名称拼写错误导致自动过滤了本来需要输入的字段,导致写入数据库的数据不完整。
从GoFrame v1.15.7
版本开始,根据社区整体反馈,为提高组件易用性,filter
特性被设置为默认开启,不再需要显示调用,Filter
方法已被标记废弃。
- No labels
17 Comments
kim
发现
OmitEmpty
()方法对于save
操作无效。调了此方法后,save
一个有部分空值字段的结构体会报错。郭强
具体什么报错信息?是数据表字段设置为
NOT NULL
了但是程序被过滤空值了吗?kim
用Save()方法进行修改的时候:比如一个5个字段的结构体,实例化一个只有2个字段有值(其中一个是主键)的对象作为Save()方法的参数,如果对象另外三个空字段(对应在数据库表中是有值的)在数据库中设置了not null约束则会报没有默认值的异常,如果不设置not null就没问题。但是正常应该是不管设不设置not null都不受影响,因为
OmitEmpty
()方法已经把结构体对象中的空字段给屏蔽了,再接着调Save()方法应该不受结构体对象参数中的空属性影响。智刚
这个其实数据库的模式有关,在就是not null的字段建议有默认值,不然哪天换数据服务器,就掉坑了
unmeme
假设有这样的一个数据表:
前端想对其进行部分更新,发送
Patch
请求因为是部分更新,所以我将请求绑定到
UserReq
上 ,并且使用了OmitEmpty()
函数当前端的请求只包含
Name
的时候,Age
属性值就是nil
,自然被过滤掉,这样就只更新Name
了但之后又发现了问题,如果前端想把
Name
更新为Null
,这该怎么办?null
绑定结构体后,是nil
,会被过滤掉在业务场景中,也不能用空字符串代替
null
,Name
空字符串代表用户无名字,null
代表用户名字未知,都是需要的请问在这种情形下,对于
Patch
请求,有什么好的数据绑定或者过滤方案吗?陈富贵
我也有这样的疑惑,请问您解决了吗
智刚
g.Map{"name":null} 不应该是写成 g.Map{"name":""} z这样吗?去掉OmitEmpty 这个方法吗?
为啥要用null 这种,是不是在设计表的时候 就是空字符串吗?
unmeme
name字符串的话,null代表用户名字未知,空字符串代表用户无名字
还有其他场景,比如合同金额int64,null代表未知,用户还没有填写合同金额,0代表合同金额为0元
我不是很喜欢用map,结构体的话比较方便,可以提示属性,也方便加tag
unmeme
还没有解决,和前端约定了某个值代表Null,暂时处理
xushushun
OmitEmpty 使用的时候非常方便,但是有一点麻烦的就是比如我有个字段 "备注"本来是有文字内容的 update的时候想更新为空白没有文字,这时候使用OmitEmpty就没办法更新这个字段了,能否考虑像,FieldsEx 那样加个OmitEmptyFieldsEx
这样就可以排除指定字段不执行OmitEmpty了
郭强
直接使用
Fields
方法指定更新字段即可,试试看。xushushun
好的我去实验下,晚点过来反馈.
刘杨
shenghong shu
OmitEmpty有时候不起效果?
如
dao.User.Ctx(ctx).OmitEmpty().Where(dao.User.C.CompanyId, req.CompanyId).WhereLike(dao.User.C.Username, req.Key)
结果
SELECT `id`,`username`,`company_id` FROM `admin_user` WHERE (`company_id`=0) AND (`username` LIKE '') LIMIT 0,20
shenghong shu
如果OmitEmpty()全局设置很麻烦,建议参考php Yii2 ORM框架的
whereFilter 在入参的时候就做过滤
FireTiger
如果要 过滤nil 跟 “” 但不过滤0 这种的要用哪个?
FireTiger
OmitEmpty 或 OmitNull 可以加个入参 控制 哪些要过滤 会更灵活一点。。