W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
查詢結(jié)果的數(shù)據(jù)結(jié)構(gòu)如下:
type Value = *gvar.Var // 返回?cái)?shù)據(jù)表記錄值
type Record map[string]Value // 返回?cái)?shù)據(jù)表記錄鍵值對(duì)
type Result []Record // 返回?cái)?shù)據(jù)表記錄列表
Value/Record/Result
?用于?ORM
?操作的結(jié)果數(shù)據(jù)類型。Result
?表示數(shù)據(jù)表記錄列表,?Record
?表示一條數(shù)據(jù)表記錄,?Value
?表示記錄中的一條鍵值數(shù)據(jù)。Value
?是?*gvar.Var
?類型的別名類型,方便于后續(xù)的數(shù)據(jù)類型轉(zhuǎn)換。接口文檔: https://pkg.go.dev/github.com/gogf/gf/v2/database/gdb
?gdb
?為數(shù)據(jù)表記錄操作提供了極高的靈活性和簡(jiǎn)便性,除了支持以?map
?的形式訪問(wèn)/操作數(shù)據(jù)表記錄以外,也支持將數(shù)據(jù)表記錄轉(zhuǎn)換為?struct
?進(jìn)行處理。我們以下使用一個(gè)簡(jiǎn)單的示例來(lái)演示該特性。
首先,我們的用戶表結(jié)構(gòu)是這樣的(簡(jiǎn)單設(shè)計(jì)的示例表):
CREATE TABLE `user` (
`uid` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL DEFAULT '' COMMENT '昵稱',
`site` varchar(255) NOT NULL DEFAULT '' COMMENT '主頁(yè)',
PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
其次,我們的表數(shù)據(jù)如下:
uid name site
1 john https://goframe.org
最后,我們的示例程序如下:
package main
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
)
type User struct {
Uid int
Name string
}
func main() {
var (
user *User
ctx = gctx.New()
)
err := g.DB().Model("user").Where("uid", 1).Scan(&user)
if err != nil {
g.Log().Header(false).Fatal(ctx, err)
}
if user != nil {
g.Log().Header(false).Print(ctx, user)
}
}
執(zhí)行后,輸出結(jié)果為:
{"Uid":1,"Name":"john"}
這里,我們自定義了一個(gè)?struct
?,里面只包含了?Uid
?和?Name
?屬性,可以看到它的屬性并不和數(shù)據(jù)表的字段一致,這也是?ORM
?靈活的特性之一:支持指定屬性獲取。
通過(guò)?gdb.Model.Scan
?方法可以將查詢到的數(shù)據(jù)記錄轉(zhuǎn)換為?struct
?對(duì)象或者?struct
?對(duì)象數(shù)組。由于這里傳遞的參數(shù)為?&user
?即?**User
?類型,那么將會(huì)轉(zhuǎn)換為一個(gè)?struct
?對(duì)象,如果傳遞為?[]*User
?類型的參數(shù),將會(huì)轉(zhuǎn)換為數(shù)組結(jié)果。
屬性字段映射規(guī)則:
需要注意的是,?map
?中的鍵名為?uid
?,?name
?,?site
?,而?struct
?中的屬性為?Uid
?,?Name
?,那么他們之間是如何執(zhí)行映射的呢?主要是以下幾點(diǎn)簡(jiǎn)單的規(guī)則:
struct
?中需要匹配的屬性必須為公開(kāi)屬性(首字母大寫(xiě));-
?/?_
?/空格符號(hào)的形式與?struct
?屬性進(jìn)行匹配;以下是幾個(gè)匹配的示例:
記錄鍵名 struct屬性 是否匹配
name Name match
Email Email match
nickname NickName match
NICKNAME NickName match
Nick-Name NickName match
nick_name NickName match
nick_name Nick_Name match
NickName Nick_Name match
Nick-Name Nick_Name match
由于數(shù)據(jù)庫(kù)結(jié)果集轉(zhuǎn)?struct
?的底層是依靠?gconv.Struct
?方法實(shí)現(xiàn)的。
?Result/Record
?數(shù)據(jù)類型根據(jù)數(shù)據(jù)結(jié)果集操作的需要,往往需要根據(jù)記錄中特定的字段作為鍵名進(jìn)行數(shù)據(jù)檢索,因此它包含多個(gè)用于轉(zhuǎn)換?Map/List
?的方法,同時(shí)也包含了常用數(shù)據(jù)結(jié)構(gòu)?JSON/XML
?的轉(zhuǎn)換方法。
接口文檔: https://pkg.go.dev/github.com/gogf/gf/v2/database/gdb
由于方法比較簡(jiǎn)單,這里便不再舉例說(shuō)明。需要注意的是兩個(gè)方法?Record.Map
?及?Result.List
?,這兩個(gè)方法也是使用比較頻繁的方法,用以將?ORM
?查詢結(jié)果信息轉(zhuǎn)換為可做展示的數(shù)據(jù)類型。由于結(jié)果集字段值底層為?[]byt
?e類型,雖然使用了新的?Value
?類型做了封裝,并且也提供了數(shù)十種常見(jiàn)的類型轉(zhuǎn)換方法,但是大多數(shù)時(shí)候需要直接將結(jié)果?Result
?或者?Record
?直接作為?json
?或者?xml
?數(shù)據(jù)結(jié)構(gòu)返回,就需要做轉(zhuǎn)換才行。
使用示例:
package main
import (
"database/sql"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
)
type User struct {
Uid int
Name string
Site string
}
func main() {
var (
user []*User
ctx = gctx.New()
)
err := g.DB().Model("user").Where("uid", 1).Scan(&user)
if err != nil && err != sql.ErrNoRows {
g.Log().Header(false).Fatal(ctx, err)
}
if user != nil {
g.Log().Header(false).Print(ctx, user)
}
}
執(zhí)行后,輸出結(jié)果為:
[{"Uid":1,"Name":"john","Site":"https://goframe.org"}]
使用?gf ORM
?對(duì)返回結(jié)果為空判斷非常簡(jiǎn)便,大部分場(chǎng)景下直接判斷返回的數(shù)據(jù)是否為?nil
?或者長(zhǎng)度為?0
?,或者使用?IsEmpty/IsNil
?方法。
r, err := g.Model("order").Where("status", 1).All()
if err != nil {
return err
}
if len(r) == 0 {
// 結(jié)果為空
}
也可以使用?IsEmpty
?方法:
r, err := g.Model("order").Where("status", 1).All()
if err != nil {
return err
}
if r.IsEmpty() {
// 結(jié)果為空
}
r, err := g.Model("order").Where("status", 1).One()
if err != nil {
return err
}
if len(r) == 0 {
// 結(jié)果為空
}
也可以使用?IsEmpty
?方法:
r, err := g.Table("order").Where("status", 1).One()
if err != nil {
return err
}
if r.IsEmpty() {
// 結(jié)果為空
}
返回的是一個(gè)"泛型"變量,這個(gè)只能使用?IsEmpty
?來(lái)判斷是否為空了。
r, err := g.Model("order").Where("status", 1).Value()
if err != nil {
return err
}
if r.IsEmpty() {
// 結(jié)果為空
}
查詢返回字段值數(shù)組本身類型為?[]gdb.Value
?類型,因此直接判斷長(zhǎng)度是否為?0
?即可。
// Array/FindArray
r, err := g.Table("order").Fields("id").Where("status", 1).Array()
if err != nil {
return err
}
if len(r) == 0 {
// 結(jié)果為空
}
關(guān)于?Struct
?轉(zhuǎn)換對(duì)象來(lái)說(shuō)會(huì)有一點(diǎn)不一樣,我們直接看例子吧。
當(dāng)傳遞的對(duì)象本身就是一個(gè)空指針時(shí),如果查詢到數(shù)據(jù),那么會(huì)在內(nèi)部自動(dòng)創(chuàng)建這個(gè)對(duì)象;如果沒(méi)有查詢到數(shù)據(jù),那么這個(gè)空指針仍舊是一個(gè)空指針,內(nèi)部并不會(huì)做任何處理。
var user *User
err := g.Model("order").Where("status", 1).Scan(&user)
if err != nil {
return err
}
if user == nil {
// 結(jié)果為空
}
當(dāng)傳遞的對(duì)象本身已經(jīng)是一個(gè)初始化的對(duì)象,如果查詢到數(shù)據(jù),那么會(huì)在內(nèi)部將數(shù)據(jù)賦值給這個(gè)對(duì)象;如果沒(méi)有查詢到數(shù)據(jù),那么此時(shí)就沒(méi)辦法將對(duì)象做?nil
?判斷空結(jié)果。因此?ORM
?會(huì)返回一個(gè)?sql.ErrNoRows
?錯(cuò)誤,提醒開(kāi)發(fā)者沒(méi)有查詢到任何數(shù)據(jù)并且對(duì)象沒(méi)有做任何賦值,對(duì)象的所有屬性還是給定的初始化數(shù)值,以便開(kāi)發(fā)者可以做進(jìn)一步的空結(jié)果判斷。
var user = new(User)
err := g.Model("order").Where("status", 1).Scan(&user)
if err != nil && err != sql.ErrNoRows {
return err
}
if err == sql.ErrNoRows {
// 結(jié)果為空
}
所以我們推薦開(kāi)發(fā)者不要傳遞一個(gè)初始化過(guò)后的對(duì)象給?ORM
?,而是直接傳遞一個(gè)對(duì)象的指針的指針類型(?**struct
?類型),?ORM
?內(nèi)部會(huì)根據(jù)查詢結(jié)果智能地做自動(dòng)初始化。
當(dāng)傳遞的對(duì)象數(shù)組本身是一個(gè)空數(shù)組(長(zhǎng)度為0),如果查詢到數(shù)據(jù),那么會(huì)在內(nèi)部自動(dòng)賦值給數(shù)組;如果沒(méi)有查詢到數(shù)據(jù),那么這個(gè)空數(shù)組仍舊是一個(gè)空數(shù)組,內(nèi)部并不會(huì)做任何處理。
var users []*User
err := g.Model("order").Where("status", 1).Scan(&users)
if err != nil {
return err
}
if len(users) == 0 {
// 結(jié)果為空
}
當(dāng)傳遞的對(duì)象數(shù)組本身不是空數(shù)組,如果查詢到數(shù)據(jù),那么會(huì)在內(nèi)部自動(dòng)從索引0位置覆蓋到數(shù)組上;如果沒(méi)有查詢到數(shù)據(jù),那么此時(shí)就沒(méi)辦法將數(shù)組做長(zhǎng)度為0判斷空結(jié)果。因此?ORM
?會(huì)返回一個(gè)?sql.ErrNoRows
?錯(cuò)誤,提醒開(kāi)發(fā)者沒(méi)有查詢到任何數(shù)據(jù)并且數(shù)組沒(méi)有做任何賦值,以便開(kāi)發(fā)者可以做進(jìn)一步的空結(jié)果判斷。
var users = make([]*User, 100)
err := g.Model("order").Where("status", 1).Scan(&users)
if err != nil {
return err
}
if err == sql.ErrNoRows {
// 結(jié)果為空
}
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: