Go語言ORM包:使用worm構造查詢條件

haming 發表於 2022-07-18
Go

構造查詢條件

worm是一款方便易用的Go語言ORM庫。worm支Model方式(持結構體欄位對映)、原生SQL以及SQLBuilder三種模式來運算元據庫,並且Model方式、原生SQL以及SQLBuilder可混合使用。
Model方式、SQL builder支援鏈式API,可使用Where, And, Or, ID, In, Limit, GroupBy, OrderBy, Having等函式構造查詢條件。也可以可通過Join、LeftJoin、RightJoin來進行資料庫表之間的關聯查詢。
本文通過一些例子來說明如何使用worm來構造查詢條件。

main函式

package main
import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
    log "github.com/haming123/wego/dlog"
    "github.com/haming123/wego/worm"
)
func mysql_open(cnnstr string) (*sql.DB, error) {
    db, err := sql.Open("mysql", cnnstr)
    if err != nil {
        return nil, err
    }
    err = db.Ping()
    if err != nil {
        return nil, err
    }
    return db, nil
}
func main() {
    //建立資料連線池
    cnnstr := "user:[email protected](127.0.0.1:3306)/dbname?charset=utf8&parseTime=True"
    db_cnn, err := mysql_open(cnnstr)
    if err != nil {
        log.Error(err)
        return
    }
    //初始化ORM
    worm.InitMysql(db_cnn)
    //顯示SQL語句log
    worm.ShowSqlLog(true)
}

說明:

  • worm程式碼的下載
    go get github.com/haming123/wego
  • worm.ShowSqlLog
    worm.ShowSqlLog用於控制sql日誌的顯示,建議測試環境下開啟sql日誌的顯示的開關,這樣可以看到每個資料庫操作的sql語句以及執行時間,方便快速定位問題。
  • 資料庫的支援
    目前worm支援的資料庫有:mysql、postgres、sqlite、sqlserver, 本文的例子中採用了mysql資料庫。

資料庫表與資料模型

//建表語句
CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `passwd` varchar(32) DEFAULT NULL,
  `created` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
);

資料庫表user對應的實體類的定義如下:

type User struct {
    Id          int64       `db:"id;autoincr"`
    Name        string      `db:"name"`
    Age         int64       `db:"age"`
    Passwd      string      `db:"passwd"`
    Created     time.Time    `db:"created;n_update"`
}
func (ent *User) TableName() string {
    return "user"
}

說明:

  • worm使用名稱為"db"的Tag對映資料庫欄位,"db"後面是欄位的名稱,autoincr用於說明該欄位是自增ID,n_update用於說明該欄位不可用於update語句中。

通過ID來查詢資料

若資料庫表存在id欄位,則可以通過ID函式來查詢一條資料據記錄:

func DemoGetById() {
    var user model.User
    _, err := worm.Model(&user).ID(1).Get()
    if err != nil {
        log.Error(err)
        return
    }
    log.Debug(user)
}
//select id,name,age,passwd,created from user where id=? limit 1

執行該函式後的sql日誌為:

[S] select id,name,age,passwd,created from user where id=1 limit 1
[S] DB: time=18.816ms

通過Where函式來查詢資料

Where函式的使用類似Sprintf函式,函式的第一個引數是sql語句(where語句)模板,後面的引數是模板變數的值。

func DemoWhere() {
    var users []model.User
    err := worm.Model(&model.User{}).Where("id>? and age>?", 1, 10).Find(&users)
    if err != nil {
        log.Error(err)
        return
    }
}
//對應的sql語句為:
//select id,name,age,passwd,created from user where id>? and age>?

說明:

  • worm佔位符統一使用?,worm會根據資料庫型別,自動替換佔位符,例如postgresql資料庫把?替換成$1,$2...
  • 可以在Where函式使用多個變數進行查詢,這種方式比較直觀,與資料庫查詢中的sql語句的寫法比較類似。但是當查詢條件比較多時,建議使用And、OR函式進行適當的分割,防止將查詢變數與變數的值對應錯誤。例如:
func DemoWhere2() {
    var users []model.User
    err := worm.Model(&model.User{}).Where("id>?", 1).And("age>?", 10).Find(&users)
    if err != nil {
        log.Error(err)
        return
    }
}
//對應的sql語句為:
//select id,name,age,passwd,created from user where id>? and age>?
  • like查詢的寫法
    例如查詢使用者的姓名中包含:demo的資料庫記錄:

    func DemoWhereLike() {
      var users []model.User
      err := worm.Model(&model.User{}).Where("name like ?", "%demo%").Find(&users)
      if err != nil {
          log.Error(err)
          return
      }
    }
    //對應的sql語句為:
    //select id,name,age,passwd,created from user where name like '%demo%'

XXXIf查詢

有些情況加我們會根據變數的值來判斷使用使用一個變數來作為查詢條件來查詢書庫,例如,若使用者的姓名不為空時通過使用者姓名來查詢資料庫。常規的寫法如下:

func DemoWhereIf(name string) {
    var users []model.User
    var err error
    if name == "" {
        err = worm.Model(&model.User{}).Find(&users)
    } else {
        err = worm.Model(&model.User{}).Where("name=?", name).Find(&users)
    }
    if err != nil {
        log.Error(err)
        return
    }
}

worm提供了更為簡單的方法(提供了WhereIf、AndIf、OrIf函式)來支援這種查詢需求:

func DemoWhereIf(name string) {
    var users []model.User
    err := worm.Model(&model.User{}).WhereIf(name != "", "name=?", name).Find(&users)
    if err != nil {
        log.Error(err)
        return
    }
}

說明:

  • WhereIf函式的第一個引數時一個bool變數,若該變數為true,則會新增查詢條件,否則忽略該查詢條件。

in、not in查詢

worm提供了AndIn、AndNotIn、OrIn、OrNotIn函式來支援sql語句中的in、not in查詢。例如:

func DemoWhereIn() {
    var users []model.User
    err := worm.Model(&model.User{}).Where("").AndIn("id", 11, 12, 13, 14).Find(&users)
    if err != nil {
        log.Error(err)
        return
    }
}
//對應的sql語句為:
select id,name,age,passwd,created from user where id in (?,?,?,?)

XXXIn、XXXNotIn的第二個引數時一個變長引數,您可以將需要查詢的值作為變長引數傳入,也可以將查詢的值放到一個陣列中進行查詢:

func DemoWhereIn() {
    var users []model.User
    arr_id := []int64{11, 12, 13, 14}
    err := worm.Model(&model.User{}).Where("").AndIn("id", arr_id).Find(&users)
    if err != nil {
        log.Error(err)
        return
    }
}

說明:

  • 若使用陣列方式,則可變長引數智慧時一個引數,並且該引數為陣列型別。

巢狀查詢語句

worm支援巢狀查詢語句,例如查詢為:age>10 and (name='demo1' or name='demo2'), 則使用worm的方式如下:

func DemoWhereExp() {
    var users []model.User
    sqlw := worm.SQLW("name=?", "demo1").Or("name=?", "demo2")
    err := worm.Model(&model.User{}).Where("age>?", 10).AndExp(sqlw).Find(&users)
    if err != nil {
        log.Error(err)
        return
    }
}
//對應的sql語句為:
//select id,name,age,passwd,created from user where age>? and (name=? or name=?)

Limit與Offset

在MySQL語句中可以使用Limit與Offset來查詢資料庫,這種查詢通常用於WEB的分頁查詢中。worm也支援mysql的Limit與Offset語句:

func DemoQueryPage(plen int64, pcur int64) {
    var users []model.User
    err := worm.Model(&model.User{}).Where("age>?", 10).Limit(plen).Offset(plen * pcur).Find(&users)
    if err != nil {
        log.Error(err)
        return
    }
}
//對應的sql語句為:
//select id,name,age,passwd,created from user where age>? limit ?, ? 

orderby查詢

OrderBy函式對應sql語句中的order by語句:

func DemoQueryOrderBy(orderby string) {
    var users []model.User
    err := worm.Model(&model.User{}).Where("age>?", 10).OrderBy(orderby).Find(&users)
    if err != nil {
        log.Error(err)
        return
    }
}
//對應的sql語句為:
//select id,name,age,passwd,created from user where age>? order by created desc