golang利用模板生成数据库表对应的模型及操作函数
起因 很多年以前,当我第一次接触到ORM的时候,我就有一点疑惑:这玩意用起来倒是方便,就是模型结构得一个字段一个字段的写,非常枯燥也非常累人,而且如果表结构修改了,比如增加、减少或者修改了一个字段,就得修改模型文件。那个时候也没有想到可以从数据库中读取到目标表的表结构数据自动生成ORM需要的模型结构。直到有一天我看到一个根据模板自动生成ORM的模型文件的代码,然后我就用golang也写了这么一个玩意。完整的代码在这里。 生成过程准备工作假设我在mysql中创建了一个名为dbnote的库,并且创建了一个名为msg的表,创建语句如下: CREATE TABLE msg ( id int(11) NOT NULL AUTO_INCREMENT,sender_id int(11) NOT NULL COMMENT '发送者',receiver_id int(11) NOT NULL COMMENT '接收者',content varchar(256) NOT NULL COMMENT '内容',status tinyint(4) NOT NULL,createtime timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (id) );
那么对应的ORM模型则是 type Msg struct {
ID int `db:"id" json:"id"` //
SenderID int `db:"sender_id" json:"sender_id"` // 发送者
ReceiverID int `db:"receiver_id" json:"receiver_id"` // 接收者
Content string `db:"content" json:"content"` // 内容
Status int8 `db:"status" json:"status"` //
Createtime *time.Time `db:"createtime" json:"createtime"` //
}
获取表结构信息 为了生成这个struct以及相关的增删改查代码,我需要先获得这个表的结果信息,以及编写对应的模板文件用于代码生成。 SELECT table_name from tables where table_schema='dbnote'
可以获取到这个库中所有的表名(当然,也可以增加过滤条件筛选目标表)。 用目标表的名称通过查询语句 SELECT COLUMN_NAME,DATA_TYPE,COLUMN_KEY,COLUMN_COMMENT from COLUMNS where TABLE_NAME='msg' and table_schema = 'dbnote'
可以获取这个表的结构信息。 type TABLE_SCHEMA struct {
COLUMN_NAME string `db:"COLUMN_NAME" json:"column_name"`
DATA_TYPE string `db:"DATA_TYPE" json:"data_type"`
COLUMN_KEY string `db:"COLUMN_KEY" json:"column_key"`
COLUMN_COMMENT string `db:"COLUMN_COMMENT" json:"COLUMN_COMMENT"`
}
生成模型及操作函数需要的全部信息,则用这样一个struct存储 type ModelInfo struct {
BDName string
DBConnection string
TableName string
PackageName string
ModelName string
TableSchema *[]TABLE_SCHEMA
}
生成struct初始化模板对象的代码是这样的 data,_ := ioutil.ReadFile("../modeltool/model.tpl")
render := template.Must(template.New("model").
Funcs(template.FuncMap{
"FirstCharUpper": modeltool.FirstCharUpper,"TypeConvert": modeltool.TypeConvert,"Tags": modeltool.Tags,"ExportColumn": modeltool.ExportColumn,"Join": modeltool.Join,"MakeQuestionMarkList": modeltool.MakeQuestionMarkList,"ColumnAndType": modeltool.ColumnAndType,"ColumnWithPostfix": modeltool.ColumnWithPostfix,}).
Parse(string(data)))
函数的定义参见代码。 填充好一个ModelInfo对象后,就可以生成代码文件了 if err := render.Execute(f,model); err != nil {
log.Fatal(err)
}
fmt.Println(fileName)
cmd := exec.Command("goimports","-w",fileName)
cmd.Run()
最后用goimports添加需要import的package,并且goimports竟然连format工作都做了,简直太爽。 相关模板语法说明
{{$exportModelName := .ModelName | FirstCharUpper}}
type {{$exportModelName}} struct
{{.COLUMN_NAME | ExportColumn}}
{{range .TableSchema}} {{.COLUMN_NAME | ExportColumn}} {{.DATA_TYPE | TypeConvert}} {{.COLUMN_NAME | Tags}} // {{.COLUMN_COMMENT}} {{end}}}
{{ColumnWithPostfix .PkColumns "=?" " and "}}"
函数的定义是 func ColumnWithPostfix(columns []string,Postfix,sep string) string {
result := make([]string, 0,len(columns))
for _,t := range columns {
result = append(result,t+Postfix)
}
return strings.Join(result,sep)
}
{{range $K:=.PkColumns}}{{$K}},{{end}}
增删改查代码的自动生成没有什么需要特别说明的,具体参见代码。 一点说明代码的目录结构是这样的 |____dbnotes
| |____dbhelper
| | |____dbhelper.go
| |____dbnote.go
| |____init.go
| |____model
| | |____mail.go
| | |____msg.go
| | |____notice.go
| |____modelgenerator
| | |____modelgenerator.go
| |____modeltool
| | |____model.tpl
| | |____modeltool.go
modelgenerator.go 编译后,运行modelgenerator可根据model.tpl将struct及操作函数生成源码文件,存放在model目录下mail.go、msg.go、notice.go的这3个源码文件就是自动生成的。3个表的创建命令在init.go的注释代码中。 一点问题由于golang的基本类型都有一个默认的初始值,不存在定义后没有初始化的变量。所以对于数据库中的NULL就没有一个比较好的直接处理的方式,如果将struct中的数据类型定义为类似这样 Content *string
倒是可以接收有内容的值以及NULL,但是这样以来,对于Content的取值和赋值就没那么方便了,当然也可以用NullString。鉴于golang的基本类型都有一个默认的初始值,我个人觉得表里面还是设定为不接受NULL值比较好。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |