新聞中心
一、設(shè)計(jì)背景
大家都知道易用性和易維護(hù)性一直是?GOframe?一直努力建設(shè)的,也是?GoFrame?有別其他框架和組件比較大的一點(diǎn)差異。?goframe?沒(méi)有采用其他?ORM?常見(jiàn)的?BelongsTo?, ?HasOne?, ?HasMany?, ?ManyToMany?這樣的模型關(guān)聯(lián)設(shè)計(jì),這樣的關(guān)聯(lián)關(guān)系維護(hù)較繁瑣,例如外鍵約束、額外的標(biāo)簽備注等,對(duì)開(kāi)發(fā)者有一定的心智負(fù)擔(dān)。因此框架不傾向于通過(guò)向模型結(jié)構(gòu)體中注入過(guò)多復(fù)雜的標(biāo)簽內(nèi)容、關(guān)聯(lián)屬性或方法,并一如既往地嘗試著簡(jiǎn)化設(shè)計(jì),目標(biāo)是使得模型關(guān)聯(lián)查詢(xún)盡可能得易于理解、使用便捷。因此在之前推出了?ScanList?方案。

創(chuàng)新互聯(lián)成立于2013年,是專(zhuān)業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目成都網(wǎng)站制作、成都網(wǎng)站設(shè)計(jì)、外貿(mào)營(yíng)銷(xiāo)網(wǎng)站建設(shè)網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元蓋州做網(wǎng)站,已為上家服務(wù),為蓋州各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話(huà):18982081108
經(jīng)過(guò)一系列的項(xiàng)目實(shí)踐,我們發(fā)現(xiàn)?ScanList?雖然從運(yùn)行時(shí)業(yè)務(wù)邏輯的角度來(lái)維護(hù)了模型關(guān)聯(lián)關(guān)系,但是這種關(guān)聯(lián)關(guān)系維護(hù)也不如期望的簡(jiǎn)便。因此,我們繼續(xù)改進(jìn)推出了可以通過(guò)模型簡(jiǎn)單維護(hù)關(guān)聯(lián)關(guān)系的?With?模型關(guān)聯(lián)特性,當(dāng)然,這種特性仍然致力于提升整體框架的易用性和維護(hù)性,可以把?With?特性看做?ScanList?與模型關(guān)聯(lián)關(guān)系維護(hù)的一種結(jié)合和改進(jìn)。
?With?特性從?goframe v1.15.7?版本開(kāi)始提供,目前屬于實(shí)驗(yàn)性特性。
二、舉個(gè)例子
我們先來(lái)一個(gè)簡(jiǎn)單的示例,便于大家更好理解?With?特性,該示例來(lái)自于之前的?ScanList?章節(jié)的相同示例,改進(jìn)版。
1、數(shù)據(jù)結(jié)構(gòu)
# 用戶(hù)表
CREATE TABLE `user` (
id int(10) unsigned NOT NULL AUTO_INCREMENT,
name varchar(45) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# 用戶(hù)詳情
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;
# 用戶(hù)學(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,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2、數(shù)據(jù)結(jié)構(gòu)
根據(jù)表定義,我們可以得知:
- 用戶(hù)表與用戶(hù)詳情是?
1:1?關(guān)系。 - 用戶(hù)表與用戶(hù)學(xué)分是?
1:N?關(guān)系。 - 這里并沒(méi)有演示?
N:N?的關(guān)系,因?yàn)橄啾容^于?1:N?的查詢(xún)只是多了一次關(guān)聯(lián)、或者一次查詢(xún),最終處理方式和?1:N?類(lèi)似。
那么Golang的模型可定義如下:
// 用戶(hù)詳情
type UserDetail struct {
gmeta.Meta `orm:"table:user_detail"`
Uid int `json:"uid"`
Address string `json:"address"`
}
// 用戶(hù)學(xué)分
type UserScores struct {
gmeta.Meta `orm:"table:user_scores"`
Id int `json:"id"`
Uid int `json:"uid"`
Score int `json:"score"`
}
// 用戶(hù)信息
type User struct {
gmeta.Meta `orm:"table:user"`
Id int `json:"id"`
Name string `json:"name"`
UserDetail *UserDetail `orm:"with:uid=id"`
UserScores []*UserScores `orm:"with:uid=id"`
}
3、數(shù)據(jù)寫(xiě)入
為簡(jiǎn)化示例,我們這里創(chuàng)建5條用戶(hù)數(shù)據(jù),采用事務(wù)操作方式寫(xiě)入:
- 用戶(hù)信息,?
id?為1-5,?name?為name_1到name_5。 - 同時(shí)創(chuàng)建5條用戶(hù)詳情數(shù)據(jù),?
address?數(shù)據(jù)為address_1到address_5。 - 每個(gè)用戶(hù)創(chuàng)建5條學(xué)分信息,學(xué)分為1-5。
db.Transaction(func(tx *gdb.TX) error {
for i := 1; i <= 5; i++ {
// User.
user := User{
Name: fmt.Sprintf(`name_%d`, i),
}
lastInsertId, err := db.Model(user).Data(user).OmitEmpty().InsertAndGetId()
if err != nil {
return err
}
// Detail.
userDetail := UserDetail{
Uid: int(lastInsertId),
Address: fmt.Sprintf(`address_%d`, lastInsertId),
}
_, err = db.Model(userDetail).Data(userDetail).OmitEmpty().Insert()
if err != nil {
return err
}
// Scores.
for j := 1; j <= 5; j++ {
userScore := UserScores{
Uid: int(lastInsertId),
Score: j,
}
_, err = db.Model(userScore).Data(userScore).OmitEmpty().Insert()
if err != nil {
return err
}
}
}
return nil
})
執(zhí)行成功后,數(shù)據(jù)庫(kù)數(shù)據(jù)如下:
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| user |
| user_detail |
| user_score |
+----------------+
3 rows in set (0.01 sec)
mysql> select * from `user`;
+----+--------+
| id | name |
+----+--------+
| 1 | name_1 |
| 2 | name_2 |
| 3 | name_3 |
| 4 | name_4 |
| 5 | name_5 |
+----+--------+
5 rows in set (0.01 sec)
mysql> select * from `user_detail`;
+-----+-----------+
| uid | address |
+-----+-----------+
| 1 | address_1 |
| 2 | address_2 |
| 3 | address_3 |
| 4 | address_4 |
| 5 | address_5 |
+-----+-----------+
5 rows in set (0.00 sec)
mysql> select * from `user_score`;
+----+-----+-------+
| id | uid | score |
+----+-----+-------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 1 | 4 |
| 5 | 1 | 5 |
| 6 | 2 | 1 |
| 7 | 2 | 2 |
| 8 | 2 | 3 |
| 9 | 2 | 4 |
| 10 | 2 | 5 |
| 11 | 3 | 1 |
| 12 | 3 | 2 |
| 13 | 3 | 3 |
| 14 | 3 | 4 |
| 15 | 3 | 5 |
| 16 | 4 | 1 |
| 17 | 4 | 2 |
| 18 | 4 | 3 |
| 19 | 4 | 4 |
| 20 | 4 | 5 |
| 21 | 5 | 1 |
| 22 | 5 | 2 |
| 23 | 5 | 3 |
| 24 | 5 | 4 |
| 25 | 5 | 5 |
+----+-----+-------+
25 rows in set (0.00 sec)
4、數(shù)據(jù)查詢(xún)
新的?With?特性下,數(shù)據(jù)查詢(xún)相當(dāng)簡(jiǎn)便,例如,我們查詢(xún)一條數(shù)據(jù):
var user *User
db.Model(tableUser).WithAll().Where("id", 3).Scan(&user)
以上語(yǔ)句您將會(huì)查詢(xún)到用戶(hù)?ID?為3的用戶(hù)信息、用戶(hù)詳情以及用戶(hù)學(xué)分信息,以上語(yǔ)句將會(huì)在數(shù)據(jù)庫(kù)中自動(dòng)執(zhí)行以下?SQL?語(yǔ)句:
2021-05-02 22:29:52.634 [DEBU] [ 2 ms] [default] SHOW FULL COLUMNS FROM `user`
2021-05-02 22:29:52.635 [DEBU] [ 1 ms] [default] SELECT * FROM `user` WHERE `id`=3 LIMIT 1
2021-05-02 22:29:52.636 [DEBU] [ 1 ms] [default] SHOW FULL COLUMNS FROM `user_detail`
2021-05-02 22:29:52.637 [DEBU] [ 1 ms] [default] SELECT `uid`,`address` FROM `user_detail` WHERE `uid`=3 LIMIT 1
2021-05-02 22:29:52.643 [DEBU] [ 6 ms] [default] SHOW FULL COLUMNS FROM `user_score`
2021-05-02 22:29:52.644 [DEBU] [ 0 ms] [default] SELECT `id`,`uid`,`score` FROM `user_score` WHERE `uid`=3
執(zhí)行后,通過(guò)?g.Dump(user)?打印的用戶(hù)信息如下:
{
"id": 3,
"name": "name_3",
"UserDetail": {
"uid": 3,
"address": "address_3"
},
"UserScores": [
{
"id": 11,
"uid": 3,
"score": 1
},
{
"id": 12,
"uid": 3,
"score": 2
},
{
"id": 13,
"uid": 3,
"score": 3
},
{
"id": 14,
"uid": 3,
"score": 4
},
{
"id": 15,
"uid": 3,
"score": 5
}
]
}
5、列表查詢(xún)
我們來(lái)一個(gè)通過(guò)?With?特性查詢(xún)列表的示例:
var users []*User
db.Model(users).With(UserDetail{}).Where("id>?", 3).Scan(&users)
執(zhí)行后,通過(guò)?g.Dump(users)?打印用戶(hù)數(shù)據(jù)如下:
[
{
"id": 4,
"name": "name_4",
"UserDetail": {
"uid": 4,
"address": "address_4"
},
"UserScores": null
},
{
"id": 5,
"name": "name_5",
"UserDetail": {
"uid": 5,
"address": "address_5"
},
"UserScores": null
}
]
6、條件與排序
通過(guò)?With?特性關(guān)聯(lián)時(shí)可以指定關(guān)聯(lián)的額外條件,以及在多數(shù)據(jù)結(jié)果下指定排序規(guī)則。例如:
type User struct {
gmeta.Meta `orm:"table:user"`
Id int `json:"id"`
Name string `json:"name"`
UserDetail *UserDetail `orm:"with:uid=id, where:uid > 3"`
UserScores []*UserScores `orm:"with:uid=id, where:score>1 and score<5, order:score desc"`
}
通過(guò)?orm?標(biāo)簽中的?where?子標(biāo)簽以及?order?子標(biāo)簽指定額外關(guān)聯(lián)條件體積排序規(guī)則。
三、詳細(xì)說(shuō)明
想必您一定對(duì)上面的某些使用比較好奇,比如?gmeta?包、比如?WithAll?方法、比如?orm?標(biāo)簽中的?with?語(yǔ)句、比如?Model?方法給定?struct?參數(shù)識(shí)別數(shù)據(jù)表名等等,那這就對(duì)啦,接下來(lái),我們?cè)敿?xì)聊聊吧。
1、gmeta包
我們可以看到在上面的結(jié)構(gòu)體數(shù)據(jù)結(jié)構(gòu)中都使用?embed?方式嵌入了一個(gè)?gmeta.Meta?結(jié)構(gòu)體,例如:
type UserDetail struct {
gmeta.Meta `orm:"table:user_detail"`
Uid int `json:"uid"`
Address string `json:"address"`
}
其實(shí)在?GoFrame?框架中有很多這種小組件包用以實(shí)現(xiàn)特定的便捷功能。?gmeta?包的作用主要用于嵌入到用戶(hù)自定義的結(jié)構(gòu)體中,并且通過(guò)標(biāo)簽的形式給?gmeta?包的結(jié)構(gòu)體(例如這里的?gmeta.Meta?)打上自定義的標(biāo)簽內(nèi)容(列如這里的?`orm:"table:user_detail"`?),并在運(yùn)行時(shí)可以特定方法動(dòng)態(tài)獲取這些自定義的標(biāo)簽內(nèi)容。
因此,這里嵌入?gmeta.Meta?的目的是為了標(biāo)記該結(jié)構(gòu)體關(guān)聯(lián)的數(shù)據(jù)表名稱(chēng)。
2、模型關(guān)聯(lián)指定
在如下結(jié)構(gòu)體中:
type User struct {
gmeta.Meta `orm:"table:user"`
Id int `json:"id"`
Name string `json:"name"`
UserDetail *UserDetail `orm:"with:uid=id"`
UserScores []*UserScore `orm:"with:uid=id"`
}
我們通過(guò)給指定的結(jié)構(gòu)體屬性綁定?orm?標(biāo)簽,并在?orm?標(biāo)簽中通過(guò)?with?語(yǔ)句指定當(dāng)前結(jié)構(gòu)體(數(shù)據(jù)表)與目標(biāo)結(jié)構(gòu)體(數(shù)據(jù)表)的關(guān)聯(lián)關(guān)系,?with?語(yǔ)句的語(yǔ)法如下:
with:當(dāng)前屬性對(duì)應(yīng)表關(guān)聯(lián)字段=當(dāng)前結(jié)構(gòu)體對(duì)應(yīng)數(shù)據(jù)表關(guān)聯(lián)字段
并且字段名稱(chēng)忽略大小寫(xiě)以及特殊字符匹配,例如以下形式的關(guān)聯(lián)關(guān)系都是能夠自動(dòng)識(shí)別的:
with:UID=ID
with:Uid=Id
with:U_ID=id
如果兩個(gè)表的關(guān)聯(lián)字段都是同一個(gè)名稱(chēng),那么也可以直接寫(xiě)一個(gè)即可,例如:
with:uid
在本示例中,?UserDetail?屬性對(duì)應(yīng)的數(shù)據(jù)表為?user_detail?,?UserScores?屬性對(duì)應(yīng)的數(shù)據(jù)表為?user_score?,兩者與當(dāng)前?User?結(jié)構(gòu)體對(duì)應(yīng)的表?user?都是使用?uid?進(jìn)行關(guān)聯(lián),并且目標(biāo)關(guān)聯(lián)的?user?表的對(duì)應(yīng)字段為?id?。
3、With/WithAll
1、基本介紹
默認(rèn)情況下,即使我們的結(jié)構(gòu)體屬性中的?orm?標(biāo)簽帶有?with?語(yǔ)句,?ORM?組件并不會(huì)默認(rèn)啟用?With?特性進(jìn)行關(guān)聯(lián)查詢(xún),而是需要依靠?With/WithAll?方法啟用該查詢(xún)特性。
- ?
With?:指定啟用關(guān)聯(lián)查詢(xún)的數(shù)據(jù)表,通過(guò)給定的屬性對(duì)象指定。 - ?
WithAll?:?jiǎn)⒂貌僮鲗?duì)象中所有帶有?with?語(yǔ)句的屬性結(jié)構(gòu)體關(guān)聯(lián)查詢(xún)。
這兩個(gè)方法的定義如下:
// With creates and returns an ORM model based on meta data of given object.
// It also enables model association operations feature on given `object`.
// It can be called multiple times to add one or more objects to model and enable
// their mode association operations feature.
// For example, if given struct definition:
// type User struct {
// gmeta.Meta `orm:"table:user"`
// Id int `json:"id"`
// Name string `json:"name"`
// UserDetail *UserDetail `orm:"with:uid=id"`
// UserScores []*UserScores `orm:"with:uid=id"`
// }
// We can enable model association operations on attribute `UserDetail` and `UserScores` by:
// db.With(User{}.UserDetail).With(User{}.UserDetail).Scan(xxx)
// Or:
// db.With(UserDetail{}).With(UserDetail{}).Scan(xxx)
// Or:
// db.With(UserDetail{}, UserDetail{}).Scan(xxx)
func (m *Model) With(objects ...interface{}) *Model
// WithAll enables model association operations on all objects that have "with" tag in the struct.
func (m *Model) WithAll() *Model
在我們本示例中,使用的是?WithAll?方法,因此自動(dòng)啟用了?User?表中的所有屬性的模型關(guān)聯(lián)查詢(xún),只要屬性結(jié)構(gòu)體關(guān)聯(lián)了數(shù)據(jù)表,并且?orm?標(biāo)簽中帶有?with?語(yǔ)句,那么都將會(huì)自動(dòng)查詢(xún)數(shù)據(jù)并根據(jù)模型結(jié)構(gòu)的關(guān)聯(lián)關(guān)系進(jìn)行數(shù)據(jù)綁定。假如我們只啟用某部分關(guān)聯(lián)查詢(xún),并不啟用全部屬性模型的關(guān)聯(lián)查詢(xún),那么可以使用?With?方法來(lái)指定。并且?With?方法可以指定啟用多個(gè)關(guān)聯(lián)模型的自動(dòng)查詢(xún),在本示例中的?WithAll?就相當(dāng)于:
var user *User
db.Model(tableUser).With(UserDetail{}, UserScore{}).Where("id", 3).Scan(&user)
也可以這樣:
var user *User
db.Model(tableUser).With(User{}.UserDetail, User{}.UserScore).Where("id", 3).Scan(&user)
2、僅關(guān)聯(lián)用戶(hù)詳情模型
假如我們只需要查詢(xún)用戶(hù)詳情,并不需要查詢(xún)用戶(hù)學(xué)分,那么我們可以使用?With?方法來(lái)啟用指定對(duì)象對(duì)應(yīng)數(shù)據(jù)表的關(guān)聯(lián)查詢(xún),例如:
var user *User
db.Model(tableUser).With(UserDetail{}).Where("id", 3).Scan(&user)
也可以這樣:
var user *User
db.Model(tableUser).With(User{}.UserDetail).Where("id", 3).Scan(&user)
執(zhí)行后,通過(guò)?g.Dump(user)?打印用戶(hù)數(shù)據(jù)如下:
{
"id": 3,
"name": "name_3",
"UserDetail": {
"uid": 3,
"address": "address_3"
},
"UserScores": null
}
3、僅關(guān)聯(lián)用戶(hù)學(xué)分模型
我們也可以只關(guān)聯(lián)查詢(xún)用戶(hù)學(xué)分信息,例如:
var user *User
db.Model(tableUser).With(UserScore{}).Where("id", 3).Scan(&user)
也可以這樣:
var user *User
db.Model(tableUser).With(User{}.UserScore).Where("id", 3).Scan(&user)
執(zhí)行后,通過(guò)?g.Dump(user)?打印用戶(hù)數(shù)據(jù)如下:
{
"id": 3,
"name": "name_3",
"UserDetail": null,
"UserScores": [
{
"id": 11,
"uid": 3,
"score": 1
},
{
"id": 12,
"uid": 3,
"score": 2
},
{
"id": 13,
"uid": 3,
"score": 3
},
{
"id": 14,
"uid": 3,
"score": 4
},
{
"id": 15,
"uid": 3,
"score": 5
}
]
}
4、不關(guān)聯(lián)任何模型查詢(xún)
假如,我們不需要關(guān)聯(lián)查詢(xún),那么更簡(jiǎn)單,例如:
var user *User
db.Model(tableUser).Where("id", 3).Scan(&user)
執(zhí)行后,通過(guò)?g.Dump(user)?打印用戶(hù)數(shù)據(jù)如下:
{
"id": 3,
"name": "name_3",
"UserDetail": null,
"UserScores": null
}
四、使用限制
1、字段查詢(xún)與過(guò)濾
可以看到,在我們上面的示例中,并沒(méi)有指定查詢(xún)的字段,但是在打印的?SQL?日志中可以看到查詢(xún)語(yǔ)句不是簡(jiǎn)單的?SELECT *?而是執(zhí)行了具體的字段查詢(xún)。在?With?特性下,將會(huì)自動(dòng)按照關(guān)聯(lián)模型對(duì)象的屬性進(jìn)行查詢(xún),屬性的名稱(chēng)將會(huì)與數(shù)據(jù)表的字段做自動(dòng)映射,并且會(huì)自動(dòng)過(guò)濾掉無(wú)法自動(dòng)映射的字段查詢(xún)。
所以,在?With?特性下,我們無(wú)法做到僅查詢(xún)屬性中對(duì)應(yīng)的某幾個(gè)字段。如果需要實(shí)現(xiàn)僅查詢(xún)并賦值某幾個(gè)字段,建議您對(duì)?model?數(shù)據(jù)結(jié)構(gòu)按照業(yè)務(wù)場(chǎng)景進(jìn)行裁剪,創(chuàng)建滿(mǎn)足特定業(yè)務(wù)場(chǎng)景的數(shù)據(jù)結(jié)構(gòu),而不是使用一個(gè)數(shù)據(jù)結(jié)構(gòu)滿(mǎn)足不同的多個(gè)場(chǎng)景。
我們來(lái)一個(gè)示例更好說(shuō)明。假如我們有一個(gè)實(shí)體對(duì)象數(shù)據(jù)結(jié)構(gòu)?Content?,一個(gè)常見(jiàn)的?CMS?系統(tǒng)的內(nèi)容模型,與數(shù)據(jù)表字段一一對(duì)應(yīng):
type Content struct {
Id uint `orm:"id,primary" json:"id"` // 自增ID
Key string `orm:"key" json:"key"` // 唯一鍵名,用于程序硬編碼,一般不常用
Type string `orm:"type" json:"type"` // 內(nèi)容模型: topic, ask, article等,具體由程序定義
CategoryId uint `orm:"category_id" json:"category_id"` // 欄目ID
UserId uint `orm:"user_id" json:"user_id"` // 用戶(hù)ID
Title string `orm:"title" json:"title"` // 標(biāo)題
Content string `orm:"content" json:"content"` // 內(nèi)容
Sort uint `orm:"sort" json:"sort"` // 排序,數(shù)值越低越靠前,默認(rèn)為添加時(shí)的時(shí)間戳,可用于置頂
Brief string `orm:"brief" json:"brief"` // 摘要
Thumb string `orm:"thumb" json:"thumb"` // 縮略圖
Tags string `orm:"tags" json:"tags"` // 標(biāo)簽名稱(chēng)列表,以JSON存儲(chǔ)
Referer string `orm:"referer" json:"referer"` // 內(nèi)容來(lái)源,例如github/gitee
Status uint `orm:"status" json:"status"` // 狀態(tài) 0: 正常, 1: 禁用
ReplyCount uint `orm:"reply_count" json:"reply_count"` // 回復(fù)數(shù)量
ViewCount uint `orm:"view_count" json:"view_count"` // 瀏覽數(shù)量
ZanCount uint `orm:"zan_count" json:"zan_count"` // 贊
CaiCount uint `orm:"cai_count" json:"cai_count"` // 踩
CreatedAt *gtime.Time `orm:"created_at" json:"created_at"` // 創(chuàng)建時(shí)間
UpdatedAt *gtime.Time `orm:"updated_at" json:"updated_at"` // 修改時(shí)間
}
內(nèi)容的列表頁(yè)又不需要展示這么詳細(xì)的內(nèi)容,特別是其中的??Content??字段非常大,我們列表頁(yè)只需要查詢(xún)幾個(gè)字段而已。那么我們可以單獨(dú)定義一個(gè)用于列表的返回?cái)?shù)據(jù)結(jié)構(gòu),而不是直接使用數(shù)據(jù)表實(shí)體對(duì)象數(shù)據(jù)結(jié)構(gòu)。例如:
type ContentListItem struct {
Id uint `json:"id"` // 自增ID
CategoryId uint `json:"category_id"` // 欄目ID
UserId uint `json:"user_id"` // 用戶(hù)ID
Title string `json:"title"` // 標(biāo)題
CreatedAt *gtime.Time `json:"created_at"` // 創(chuàng)建時(shí)間
UpdatedAt *gtime.Time `json:"updated_at"` // 修改時(shí)間
}
2、必須存在關(guān)聯(lián)字段屬性
由于?With?特性是通過(guò)識(shí)別數(shù)據(jù)結(jié)構(gòu)關(guān)聯(lián)關(guān)系并自動(dòng)執(zhí)行多條?SQL?查詢(xún)來(lái)實(shí)現(xiàn)的,因此關(guān)聯(lián)的字段也必須作為對(duì)象的屬性便于關(guān)聯(lián)字段值得自動(dòng)獲取。簡(jiǎn)單地講,?with?標(biāo)簽中的字段必須存在于關(guān)聯(lián)對(duì)象的屬性上。
五、后續(xù)改進(jìn)
目前?With?特性?xún)H實(shí)現(xiàn)了查詢(xún)操作,還不支持寫(xiě)入更新等操作。
分享文章:創(chuàng)新互聯(lián)GoFrame教程:GoFrame模型關(guān)聯(lián)-With特性
分享地址:http://m.fisionsoft.com.cn/article/dphjcsg.html


咨詢(xún)
建站咨詢(xún)
