golang?gorm學(xué)習(xí)之如何指定數(shù)據(jù)表
一、通過model名稱自動匹配表名
我們看如下例子:
type MTest struct { Id int64 Name string } func main() { dsn := "test:123456@tcp(localhlost:3306)/test01?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms" db, _ := gorm.Open(mysql.Open(dsn)) m := MTest{} db.Find(m) fmt.Println(m) fmt.Println(db.Statement.Table) }
在這個例子中,表名是通過根據(jù)model的結(jié)構(gòu)體的名字MTest來指定的。規(guī)則如下:
- 若是駝峰的形式,則兩個大小字母之間會加一個下劃線連接。
- 是結(jié)構(gòu)體名稱的復(fù)數(shù)形式。復(fù)數(shù)形式符合英文單詞的復(fù)數(shù)規(guī)則。例如若最后一個單詞是s,那么最終表名就不會再加s。比如model結(jié)構(gòu)體的名稱是a01s,那么最終的表名就是a01s。
所以,上面的表名最終是:m_tests
這種方式的實現(xiàn),本質(zhì)上是通過gorm.Open中指定的名稱策略來實現(xiàn)的。如下:
在NamingStrategy結(jié)構(gòu)體中,可以指定前綴以及是否是復(fù)數(shù)形式,如下:
func (ns NamingStrategy) TableName(str string) string { if ns.SingularTable { return ns.TablePrefix + ns.toDBName(str) } return ns.TablePrefix + inflection.Plural(ns.toDBName(str)) }
指定表前綴、禁用復(fù)數(shù)
通過在gorm.Open的函數(shù)中指定對應(yīng)的配置選項,就可以給本次連接做相關(guān)的配置。比如指定表名前綴,禁用表名復(fù)數(shù)等。如下:
type MTest struct { Id int64 Name string } func main() { dsn := "sands:123456@tcp(test.trdplace.ads.sg1.mysql:3306)/test01?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms" config := &gorm.Config{ NamingStrategy: schema.NamingStrategy{ TablePrefix: "pre_", // 表前綴 SingularTable: true, // 禁用表名復(fù)數(shù) }} db, _ := gorm.Open(mysql.Open(dsn), config) m := MTest{} db.Find(m) fmt.Println(m) fmt.Println(db.Statement.Table) }
如上,最終打印出的表名就是m_test
。
二、通過實現(xiàn)Tabler接口指定表名
第二種方式是通過讓model結(jié)構(gòu)體實現(xiàn)TableName() string 函數(shù)來指定具體的表名。如下:
type MTest struct { Id int64 Name string } func (m *MTest) TableName() string { return "m_test" }
這樣,表名就是TableName指定的字符串,指定什么就是什么。其實這個本質(zhì)上是實現(xiàn)了Tabler接口:
type Tabler interface { TableName() string }
三、通過實現(xiàn)TablerWithNamer接口指定表名
第三種方式是讓Model結(jié)構(gòu)體實現(xiàn)TablerWithNamer接口來指定表名。接口定義如下:
type TablerWithNamer interface { TableName(Namer) string }
這里的Namer也是一個接口,在第一種方式中,實際上就是指定了一個Namer,在gorm.Open函數(shù)中,我們看下:
當(dāng)然,我們也可以自己實現(xiàn)Namer接口來指定具體的表名規(guī)則。
四、通過embeddedNamer結(jié)構(gòu)體
這個是在Namer接口的基礎(chǔ)上,如果該Namer是embeddedNamer結(jié)構(gòu)體類型,那么優(yōu)先使用這個結(jié)構(gòu)體中指定的名稱。embeddedNamer結(jié)構(gòu)體如下:
type embeddedNamer struct { Table string Namer }
五、查詢時直接通過db.Table函數(shù)指定表名
使用db.Table
指定的表后,gorm將不再使用自動解析出來的表名了。所以該方式的優(yōu)先級是最高的。如下:
type MTest struct { Id int64 Name string } func main() { dsn := "123456:123456@tcp(localhost:3306)/test01?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms" db, _ := gorm.Open(mysql.Open(dsn)) m := MTest{} db.Table("m_tests").Find(m) }
六、實現(xiàn)原理
還是以db.Find(m)為例。 首先,F(xiàn)ind函數(shù)會把m對象賦值給db.Statement.Dest字段。這個Dest字段就是要查詢的目標(biāo)數(shù)據(jù)。然后再調(diào)用db.callbacks.Query().Execute(tx)。就是實際的查詢函數(shù)。如下是db.Find的代碼:
func (db *DB) Find(dest interface{}, conds ...interface{}) (tx *DB) { tx = db.getInstance() if len(conds) > 0 { if exprs := tx.Statement.BuildCondition(conds[0], conds[1:]...); len(exprs) > 0 { tx.Statement.AddClause(clause.Where{Exprs: exprs}) } } tx.Statement.Dest = dest return tx.callbacks.Query().Execute(tx) }
其中tx是從原db中再獲取一個db對象,同時也具有了對應(yīng)的數(shù)據(jù)庫連接的對象。然后tx.callbacks.Query()其實就是db.Open函數(shù)中初始化的callbacks:db.callbacks = initializeCallbacks(db)
。如下:
func initializeCallbacks(db *DB) *callbacks { return &callbacks{ processors: map[string]*processor{ "create": {db: db}, "query": {db: db}, "update": {db: db}, "delete": {db: db}, "row": {db: db}, "raw": {db: db}, }, } }
其次,在processor.Execute函數(shù)中會看到,statement.Model和statement.Dest會相互賦值。如下:
最主要的是在statement.Parse函數(shù)解析的表名了。依次看代碼調(diào)用,最終會到schema.go文件中的ParseWithSpecialTableName函數(shù)中,在這個函數(shù)中,有對表名的解析。如下:
七、總結(jié)
本文總結(jié)了gorm中如何指定表名的多種方式。其中優(yōu)先級最高的是通過gorm會根據(jù)指定的model結(jié)構(gòu)體的名稱自動解析出表名。同時,如果model實現(xiàn)了Tabler接口或TablerWithNamer接口,那么就會優(yōu)先根據(jù)這兩個接口的對應(yīng)TableName函數(shù)指定的表名進行解析。
以上就是golang gorm學(xué)習(xí)之如何指定數(shù)據(jù)表的詳細(xì)內(nèi)容,更多關(guān)于gorm指定數(shù)據(jù)表的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
golang定時器Timer的用法和實現(xiàn)原理解析
這篇文章主要介紹了golang定時器Ticker,本文主要來看一下Timer的用法和實現(xiàn)原理,需要的朋友可以參考以下內(nèi)容2023-04-04Go語言學(xué)習(xí)之循環(huán)語句使用詳解
這篇文章主要為大家介紹了Go語言中的常用循環(huán)語句的使用,例如:for循環(huán)、for-each、break等,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-04-04Golang?gRPC?HTTP協(xié)議轉(zhuǎn)換示例
這篇文章主要為大家介紹了Golang?gRPC?HTTP協(xié)議轉(zhuǎn)換示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06