初学者必须明白:在Go中,没有null,none,NULL,None任何类型在未初始化时都对应一个零值:布尔类型为false,整数为0,字符串为""和指针,零值offunction,interface,slice,channelandmap都是nil结合场景,权衡利弊,不支持取舍。于是问了goframe的作者,被明确告知:goframe不支持,以后也不支持。作者也详细说明了不支持的理由。goframe作者团队的考虑是这样的:因为自己做的项目比较多,在数据库表结构管理上踩坑了。goframe作者的观点还是比较能接受的。migrate这个功能确实方便了开发者,但是在企业级项目中,尤其是TOB业务,稳定性才是重中之重。migrate函数虽然方便,但是不够严谨。如果没有强有力的规范来限制团队成员的使用,很容易出问题。万一有问题,那可不是小问题,不敢用。这也让我想起另外一件事:前段时间review代码时,发现运行了一个“无条件”的删除脚本,吓了一跳!删除数据会很麻烦。但是查询DB发现没有数据被删除。详细查看了官方文档,数据没有被删除的原因如下:goframe是一个企业生产级的框架,每个模块都经过严谨的设计,工程实践的细节处理的比较好。为了保证安全,防止误操作,Update和Delete方法必须有Where条件才能提交执行,否则会返回错误,错误信息如:shouldtherewhereconditionstatementforXXX手术。好吧,谢谢,它真的救了我狗的命,哈哈。也正是因为我做过很多项目,踩过很多坑,遇到过很多这样的细节问题。直到现在才从“追求开发效率”转变为“追求项目稳定”。这里也回答一下最近大家私信我的问题:“我这个电商实战项目为什么要用goframe框架?”原因很简单。根据我自己的经验,我认为GoFrame是一个比较严谨的框架,适合企业级项目。可以少踩坑,避免一些麻烦。虽然有进入门槛,但在“工程开发设计”标准下,后续维护成本还是比较低的。所以我才带大家用这个框架做电商项目。嗯,不同的场景,不同的项目有不同的解决方案,首选的框架也不同。这个问题没有标准答案,根据自己的需求选择合适的方案。欢迎大家与我交流,多向这位读者提出有价值的问题,共同进步!Fields/FieldsEx字段过滤Fields用于指定需要操作的表字段,包括查询字段、写入字段、更新字段等;FieldsEx用于异常字段规范,可用于查询字段、写入字段、更新字段等过滤;字段示例假设用户表有4个字段uid,nickname,passport,password。查询字段过滤//SELECT`uid`,`nickname`FROM`user`ORDERBY`uid`ascg.Model("user").Fields("uid,nickname").Order("uidasc").All()写入字段过滤器m:=g.Map{"uid":10000,"nickname":"JohnGuo","passport":"john","password":"123456",}g.Model(table).Fields("nickname,passport,password").Data(m).Insert()//INSERTINTO`user`(`nickname`,`passport`,`password`)VALUES('JohnGuo','john','123456')FieldsExExample1.假设用户表有4个字段uid,nickname,passport,password。2.查询字段排除//SELECT`uid`,`nickname`FROM`user`g.Model("user").FieldsEx("passport,password").All()3.写入字段排除m:=g。Map{"uid":10000,"昵称":"JohnGuo","passport":"john","password":"123456",}g.Model(table).FieldsEx("uid").Data(m).Insert()//INSERTINTO`user`(`nickname`,`passport`,`password`)VALUES('JohnGuo','john','123456')map/struct时省略空值过滤当存在nil、""、0等空值时,默认情况下,gdb会把它当作一个普通的输入参数,所以这些参数也会更新到数据表中。OmitEmpty功能可以在将数据写入数据库之前过滤具有空数据的字段。相关方法:func(m*Model)OmitEmpty()*Modelfunc(m*Model)OmitEmptyWhere()*Modelfunc(m*Model)OmitEmptyData()*ModelOmitEmpty方法会同时过滤Where和Data中的空数据此时,可以通过OmitEmptyWhere/OmitEmptyData方法进行特定字段过滤。写/更新操作Null值会影响写/更新操作方法,例如Insert,Replace,Update,Save操作。比如下面的操作(以map为例,struct同理)://UPDATE`user`SET`name`='john',update_time=nullWHERE`id`=1g.Model("user").Data(g.Map{"name":"john","update_time":nil,}).Where("id",1).Update()对于空值,我们可以使用OmitEmpty方法过滤掉这些空值。例如,上面的例子可以修改为://UPDATE`user`SET`name`='john'WHERE`id`=1g.Model("user").OmitEmpty().Data(g.Map{"name":"john","update_time":nil,}).Where("id",1).Update()对于structdata参数,我们也可以进行空值过滤。操作示例:typeUserstruct{idint`orm:"id"`Passportstring`orm:"passport"`Passwordstring`orm:"password"`NickNamestring`orm:"nickname"`CreateTimestring`orm:"create_time"`UpdateTimestring`orm:"update_time"`}user:=User{Id:1,NickName:"john",UpdateTime:gtime.Now().String(),}g.Model("user").OmitEmpty().Data(user).Insert()//INSERTINTO`user`(`id`,`nickname`,`update_time`)VALUES(1,'john','2019-10-0112: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'LIMIT1r,err:=g.Model("user").Where(g.Map{"nickname":"","passport":"john",}).OmitEmpty().One()typeUserstruct{Idint`orm:"id"`Passportstring`orm:"passport"`Passwordstring`orm:"password"`NickNamestring`orm:"nickname"`CreateTimestring`orm:"create_time"`UpdateTimestring`orm:"update_time"`}user:=User{Passport:"john",}r,err:=g.Model("user").OmitEmpty().Where(user).One()//SELECT*FROM`user`WHERE`passport`='john'LIMIT1OmitNil空值过滤当map/struct中有nil等空值时,通过默认情况下,gdb会把它当作一个普通的输入参数,所以这些参数也会更新到数据表中。OmitNil特性可以在将数据写入数据库之前过滤具有空值数据的字段。与OmitEmpty特性不同的是,OmitNil只过滤值为nil的空字段,其他空值如"",0不会被过滤。相关方法:func(m*Model)OmitNil()*Modelfunc(m*Model)OmitNilWhere()*Modelfunc(m*Model)OmitNilData()*ModelOmitNil方法会过滤Where和Data处的空数据同时,但是可以通过OmitNilWhere/OmitNilData方法进行特定字段的过滤。Filter字段过滤(内置)gdb可以自动将数据表结构同步到程序缓存中(缓存不会过期,直到程序重启/重新部署),可以过滤提交参数中做的数据项不符合表结构。此功能可以使用Filter方法实现。常用于增删改操作输入map/struct/[]map/[]string参数类型的场景。举个例子,如果user表有4个字段uid,nickname,passport,password:r,err:=g.Model("user").Filter().Data(g.Map{"id":1,"uid":1,"passport":"john","password":"123456",}).Insert()//INSERTINTOuser(uid,passport,password)VALUES(1,"john","123456")其中id是一个不存在的字段,在写数据的时候会被过滤掉,这样在写SQL的时候不会构造成执行错误。数据库并没有设计为Data方法进行自动过滤,而是需要开发者调用Filter方法手动指定过滤。目的是善意提醒开发者,他们可能误写/传递了错误的字段名。强制自动过滤可能会导致不可预测的业务逻辑异常。例如,由于字段名拼写错误,自动过滤了应该输入的字段,导致写入数据库的数据不完整。从GoFramev1.15.7开始,根据社区整体反馈,为了提高组件的易用性,filter特性设置为默认开启,无需显示调用,以及Filter方法已被标记为过时。本文转载自微信公众号《程序员的升级打怪之旅》,作者“王中阳围棋”,可通过以下二维码关注。转载本文请联系《程序员升级打怪之旅》公众号。
