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'
可以獲取這個表的結構資訊。 表結構的資訊用這樣一個struct儲存
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工作都做了,簡直太爽。
相關模板語法說明
- 以下語句將ModelName的值用函式FirstCharUpper處理為首字面大寫然後賦值給$exportModelName變數
{{$exportModelName := .ModelName | FirstCharUpper}}
- 以下語句使用變數$exportModelName
type {{$exportModelName}} struct
-
以下語句通過函式ExportColumn將欄位COLUMN_NAME的值中的下畫線去掉並將單詞的首字面大寫,並且將id處理成ID。ExportColumn內容參見程式碼,可以根據實際需要調整。
{{.COLUMN_NAME | ExportColumn}}
- 以下語句迴圈處理ModelInfo.TableSchema中的元素
{{range .TableSchema}} {{.COLUMN_NAME | ExportColumn}} {{.DATA_TYPE | TypeConvert}} {{.COLUMN_NAME | Tags}} // {{.COLUMN_COMMENT}} {{end}}}
- 以下語句用3個引數 .PkColumns,=?, and呼叫函式ColumnWithPostfix
{{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的註釋程式碼中。 資料庫IP地址,使用者名稱及密碼在dbhelper.go的init()函式中,DB例項用於連線mail、msg、notice所在的庫,SYSDB例項用於連線information_schema庫獲取表結構資訊。 dbnote.go是示例程式碼,示範對mail、msg、notice3個表資料的增刪改查。
一點問題
由於golang的基本型別都有一個預設的初始值,不存在定義後沒有初始化的變數。所以對於資料庫中的NULL就沒有一個比較好的直接處理的方式,如果將struct中的資料型別定義為類似這樣
Content *string
倒是可以接收有內容的值以及NULL,但是這樣以來,對於Content的取值和賦值就沒那麼方便了,當然也可以用NullString。鑑於golang的基本型別都有一個預設的初始值,我個人覺得表裡面還是設定為不接受NULL值比較好。
相關文章
- 利用wordpress的資料庫操作函式資料庫函式
- 【模板】生成函式 I函式
- Hive資料庫及表的基本操作Hive資料庫
- 利用rman生成備用資料庫操作文件資料庫
- 線上ER模型設計:視覺化MySQL資料庫建表及操作模型視覺化MySql資料庫
- Oracle資料庫管理——表資料庫高水位及shrink操作Oracle資料庫
- Laravel從已有資料庫表生成對應的migration和seed檔案Laravel資料庫
- 利用非對話語料來豐富對話生成模型模型
- 轉載:尤拉函式知識點總結及程式碼模板及尤拉函式表函式
- 利用mysqldump只匯出資料庫的表結構、儲存過程和函式MySql資料庫儲存過程函式
- 使用 powerdesigner 將資料庫表結構逆向工程生成對應的word文件資料庫
- Python利用partial偏函式生成不同的聚合函式Python函式
- 利用MySQL原資料資訊批量轉換指定庫資料表生成Hive建表語句MySqlHive
- Golang 針對 MySQL 資料庫表結構的差異 SQL 工具GolangMySql資料庫
- Mysql資料庫自定義函式的定義、使用方法及操作注意事項MySql資料庫函式
- H2資料庫函式及資料型別概述資料庫函式資料型別
- MyBatis Java 和 資料庫 資料型別對應表MyBatisJava資料庫資料型別
- abp框架寫實體類並生成對應的資料庫框架資料庫
- MySQL(一) 資料表資料庫的基本操作MySql資料庫
- 程序間通訊函式介面及應用模板小結函式
- 用Powerdesigner的PDM生成資料庫及逆向生成資料庫
- 利用ODBC實現Domino和關聯式資料庫的互操作 (轉)資料庫
- wordpress模板修改及函式說明函式
- INFORMIX資料庫函式ORM資料庫函式
- MySQL資料庫反向生成powerdesigner模型MySql資料庫模型
- Activt工作流資料庫對應表的作用資料庫
- Hybris ECP裡Customer對應的資料庫表資料庫
- [BUG反饋]生成模型掉不出資料表模型
- 值得白嫖的資料庫常用操作語句彙總(資料庫、資料表、資料操作)資料庫
- mysql迴圈插入資料、生成隨機數及CONCAT函式MySql隨機函式
- 在 mysql 下 建立新的資料庫和對應的表MySql資料庫
- 模型表示及代價函式模型函式
- SQL—對資料表內容的基本操作SQL
- 【c++】函式模板的簡單應用C++函式
- mysql資料庫一行命令生成GIN+GORM RESTful APIs Golang應用MySql資料庫ORMRESTAPIGolang
- VB與資料庫應用一例----生成EXCEL表 (轉)資料庫Excel
- 7.資料庫函式資料庫函式
- 常見python資料型別及其相對應的函式Python資料型別函式