新聞中心
?gf?的?ORM?沒有采用其他?ORM?常見的?BelongsTo?, ?HasOne?, ?HasMany?, ?ManyToMany?這樣的模型關(guān)聯(lián)設(shè)計(jì),這樣的關(guān)聯(lián)關(guān)系維護(hù)較繁瑣,例如外鍵約束、額外的標(biāo)簽備注等,對(duì)開發(fā)者有一定的心智負(fù)擔(dān)。因此?gf?框架不傾向于通過向模型結(jié)構(gòu)體中注入過多復(fù)雜的標(biāo)簽內(nèi)容、關(guān)聯(lián)屬性或方法,并一如既往地嘗試著簡化設(shè)計(jì),目標(biāo)是使得模型關(guān)聯(lián)查詢盡可能得易于理解、使用便捷。

創(chuàng)新互聯(lián)公司堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:做網(wǎng)站、成都網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的高州網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
接下來關(guān)于?gf ORM?提供的模型關(guān)聯(lián)實(shí)現(xiàn),從?GF v1.13.6?版本開始提供,目前屬于實(shí)驗(yàn)性特性。
那么我們就使用一個(gè)例子來介紹?gf ORM?提供的模型關(guān)聯(lián)吧。
數(shù)據(jù)結(jié)構(gòu)
為簡化示例,我們這里設(shè)計(jì)得表都盡可能簡單,每張表僅包含3-4個(gè)字段,方便闡述關(guān)聯(lián)關(guān)系即可。
# 用戶表
CREATE TABLE `user` (
uid int(10) unsigned NOT NULL AUTO_INCREMENT,
name varchar(45) NOT NULL,
PRIMARY KEY (uid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# 用戶詳情
CREATE TABLE `user_detail` (
uid int(10) unsigned NOT NULL AUTO_INCREMENT,
address varchar(45) NOT NULL,
PRIMARY KEY (uid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# 用戶學(xué)分
CREATE TABLE `user_scores` (
id int(10) unsigned NOT NULL AUTO_INCREMENT,
uid int(10) unsigned NOT NULL,
score int(10) unsigned NOT NULL,
course varchar(45) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
數(shù)據(jù)模型
根據(jù)表定義,我們可以得知:
- 用戶表與用戶詳情是?
1:1?關(guān)系。 - 用戶表與用戶學(xué)分是?
1:N?關(guān)系。 - 這里并沒有演示?
N:N?的關(guān)系,因?yàn)橄啾容^于?1:N?的查詢只是多了一次關(guān)聯(lián)、或者一次查詢,最終處理方式和?1:N?類似。
那么GOlang的模型可定義如下:
// 用戶表
type EntityUser struct {
Uid int `orm:"uid"`
Name string `orm:"name"`
}
// 用戶詳情
type EntityUserDetail struct {
Uid int `orm:"uid"`
Address string `orm:"address"`
}
// 用戶學(xué)分
type EntityUserScores struct {
Id int `orm:"id"`
Uid int `orm:"uid"`
Score int `orm:"score"`
Course string `orm:"course"`
}
// 組合模型,用戶信息
type Entity struct {
User *EntityUser
UserDetail *EntityUserDetail
UserScores []*EntityUserScores
}其中,?EntityUser?, ?EntityUserDetail?, ?EntityUserScores?分別對(duì)應(yīng)的是用戶表、用戶詳情、用戶學(xué)分?jǐn)?shù)據(jù)表的數(shù)據(jù)模型。?Entity?是一個(gè)組合模型,對(duì)應(yīng)的是一個(gè)用戶的所有詳細(xì)信息。
數(shù)據(jù)寫入
寫入數(shù)據(jù)時(shí)涉及到簡單的數(shù)據(jù)庫事務(wù)即可。
err := db.Transaction(func(tx *gdb.TX) error {
r, err := tx.Table("user").Save(EntityUser{
Name: "john",
})
if err != nil {
return err
}
uid, err := r.LastInsertId()
if err != nil {
return err
}
_, err = tx.Table("user_detail").Save(EntityUserDetail{
Uid: int(uid),
Address: "Beijing DongZhiMen #66",
})
if err != nil {
return err
}
_, err = tx.Table("user_scores").Save(g.Slice{
EntityUserScores{Uid: int(uid), Score: 100, Course: "math"},
EntityUserScores{Uid: int(uid), Score: 99, Course: "physics"},
})
return err
})數(shù)據(jù)查詢
單條數(shù)據(jù)記錄
查詢單條模型數(shù)據(jù)比較簡單,直接使用?Scan?方法即可,該方法會(huì)自動(dòng)識(shí)別綁定查詢結(jié)果到單個(gè)對(duì)象屬性還是數(shù)組對(duì)象屬性中。例如:
// 定義用戶列表
var user Entity
// 查詢用戶基礎(chǔ)數(shù)據(jù)
// SELECT * FROM `user` WHERE `name`='john'
err := db.Table("user").Scan(&user.User, "name", "john")
if err != nil {
return err
}
// 查詢用戶詳情數(shù)據(jù)
// SELECT * FROM `user_detail` WHERE `uid`=1
err := db.Table("user_detail").Scan(&user.UserDetail, "uid", user.User.Uid)
// 查詢用戶學(xué)分?jǐn)?shù)據(jù)
// SELECT * FROM `user_scores` WHERE `uid`=1
err := db.Table("user_scores").Scan(&user.UserScores, "uid", user.User.Uid)多條數(shù)據(jù)記錄
查詢多條數(shù)據(jù)記錄并綁定數(shù)據(jù)到數(shù)據(jù)模型數(shù)組中,需要使用到?ScanList?方法,該方法會(huì)需要用戶指定結(jié)果字段與模型屬性的關(guān)系,隨后底層會(huì)遍歷數(shù)組并自動(dòng)執(zhí)行數(shù)據(jù)綁定。例如:
// 定義用戶列表
var users []Entity
// 查詢用戶基礎(chǔ)數(shù)據(jù)
// SELECT * FROM `user`
err := db.Table("user").ScanList(&users, "User")
// 查詢用戶詳情數(shù)據(jù)
// SELECT * FROM `user_detail` WHERE `uid` IN(1,2)
err := db.Table("user_detail").
Where("uid", gdb.ListItemValuesUnique(users, "User", "Uid")).
ScanList(&users, "UserDetail", "User", "uid:Uid")
// 查詢用戶學(xué)分?jǐn)?shù)據(jù)
// SELECT * FROM `user_scores` WHERE `uid` IN(1,2)
err := db.Table("user_scores").
Where("uid", gdb.ListItemValuesUnique(users, "User", "Uid")).
ScanList(&users, "UserScores", "User", "uid:Uid")這其中涉及到兩個(gè)比較重要的方法:
1. ?ScanList?
方法定義:
// ScanList converts to struct slice which contains other complex struct attributes.
// Note that the parameter should be type of *[]struct/*[]*struct.
// Usage example:
//
// type Entity struct {
// User *EntityUser
// UserDetail *EntityUserDetail
// UserScores []*EntityUserScores
// }
// var users []*Entity
// or
// var users []Entity
//
// ScanList(&users, "User")
// ScanList(&users, "UserDetail", "User", "uid:Uid")
// ScanList(&users, "UserScores", "User", "uid:Uid")
// The parameters "User"/"UserDetail"/"UserScores" in the example codes specify the target attribute struct
// that current result will be bound to.
// The "uid" in the example codes is the table field name of the result, and the "Uid" is the relational
// struct attribute name. It automatically calculates the HasOne/HasMany relationship with given
// parameter.
// See the example or unit testing cases for clear understanding for this function.
func (m *Model) ScanList(listPointer interface{}, attributeName string, relation ...string) (err error) 該方法用于將查詢到的數(shù)組數(shù)據(jù)綁定到指定的列表上,例如:
- ?
ScanList(&users, "User")?:表示將查詢到的用戶信息數(shù)組數(shù)據(jù)綁定到?users?列表中每一項(xiàng)的?User?屬性上。 - ?
ScanList(&users, "UserDetail", "User", "uid:Uid")?:表示將查詢到用戶詳情數(shù)組數(shù)據(jù)綁定到?users?列表中每一項(xiàng)的?UserDetail?屬性上,并且和另一個(gè)?User?對(duì)象屬性通過?uid:Uid?的字段:屬性關(guān)聯(lián),內(nèi)部將會(huì)根據(jù)這一關(guān)聯(lián)關(guān)系自動(dòng)進(jìn)行數(shù)據(jù)綁定。其中?uid:Uid?前面的?uid?表示查詢結(jié)果字段中的?uid?字段,后面的?Uid?表示目標(biāo)關(guān)聯(lián)對(duì)象中的?Uid?屬性。 - ?
ScanList(&users, "UserScores", "User", "uid:Uid")?:表示將查詢到用戶詳情數(shù)組數(shù)據(jù)綁定到?users?列表中每一項(xiàng)的?UserScores?屬性上,并且和另一個(gè)?User?對(duì)象屬性通過?uid:Uid?的字段:屬性關(guān)聯(lián),內(nèi)部將會(huì)根據(jù)這一關(guān)聯(lián)關(guān)系自動(dòng)進(jìn)行數(shù)據(jù)綁定。由于?UserScores?是一個(gè)數(shù)組類型?[]*EntityUserScores?,因此該方法內(nèi)部可以自動(dòng)識(shí)別到?User?到?UserScores?其實(shí)是?1:N?的關(guān)系,自動(dòng)完成數(shù)據(jù)綁定。
需要提醒的是,如果關(guān)聯(lián)數(shù)據(jù)中對(duì)應(yīng)的關(guān)聯(lián)屬性數(shù)據(jù)不存在,那么該屬性不會(huì)被初始化并將保持?nil?。
2. ?ListItemValues/ListItemValuesUnique?
方法定義:
// ListItemValues retrieves and returns the elements of all item struct/map with key .
// Note that the parameter should be type of slice which contains elements of map or struct,
// or else it returns an empty slice.
//
// The parameter supports types like:
// []map[string]interface{}
// []map[string]sub-map
// []struct
// []struct:sub-struct
// Note that the sub-map/sub-struct makes sense only if the optional parameter is given.
func ListItemValues(list interface{}, key interface{}, subKey ...interface{}) (values []interface{})
// ListItemValuesUnique retrieves and returns the unique elements of all struct/map with key .
// Note that the parameter should be type of slice which contains elements of map or struct,
// or else it returns an empty slice.
// See gutil.ListItemValuesUnique.
func ListItemValuesUnique(list interface{}, key string, subKey ...interface{}) []interface{}
?ListItemValuesUnique?與?ListItemValues?方法的區(qū)別在于過濾重復(fù)的返回值,保證返回的列表數(shù)據(jù)中不帶有重復(fù)值。這兩個(gè)方法都會(huì)在當(dāng)給定的列表中包含?struct/map?數(shù)據(jù)項(xiàng)時(shí),用于獲取指定屬性/鍵名的數(shù)據(jù)值,構(gòu)造成數(shù)組?[]interface{}?返回。示例:
- ?
gdb.ListItemValuesUnique(users, "Uid")?用于獲取?users?數(shù)組中,每一個(gè)?Uid?屬性,構(gòu)造成?[]interface{}?數(shù)組返回。這里以便根據(jù)?uid?構(gòu)造成?SELECT...IN...?查詢。 - ?
gdb.ListItemValuesUnique(users, "User", "Uid")?用于獲取?users?數(shù)組中,每一個(gè)?User?屬性項(xiàng)中的?Uid?屬性,構(gòu)造成?[]interface{}?數(shù)組返回。這里以便根據(jù)?uid?構(gòu)造成?SELECT...IN...?查詢。
分享題目:創(chuàng)新互聯(lián)GoFrame教程:GoFrame 模型關(guān)聯(lián)-ScanList
文章分享:http://www.fisionsoft.com.cn/article/djsgici.html


咨詢
建站咨詢
