はじめに
前回の記事の続きです。
前回の記事はこちら
beedbライブラリを使用してORM開発を行う
今回は ORM開発を行います。 前回と同様の環境を使用します。
beedbライブラリとは
beedbは私が開発したGoによるORM操作のためのライブラリです。
これはGo styleの方法でデータベースに対し操作を行います。
structからテーブルの記録へのマッピングを実現します。beedbは十分軽量なGo ORMフレームワークです。
おぉ!著者の方が作成したものなのですね。
とりあえず使ってみましょう。
インストール
go get github.com/astaxie/beedb
こちらは、不要ですね。go modules
を使用しているので、 import
した際に勝手にget
してくれます。
初期化の方法
まず対応するデータベースドライバパッケージをimportする必要があります。database/sql標準インターフェースパッケージおよびbeedbパッケージです:
import (
"database/sql"
"github.com/astaxie/beedb"
_ "github.com/ziutek/mymysql/godrv"
)
インポートして、その後にデータベースを開きますと
db, err := sql.Open("mymysql", "test/xiemengjun/123456")
if err != nil {
panic(err)
}
orm := beedb.New(db)
db
を開いた後に、 beedb.New
としていますね!
beedbのNew関数は2つの引数を必要とします。
一つ目の引数は標準インターフェースのdbで、二つ目の引数は利用するデータベースエンジンです。
もしあなたが使用するデータベースエンジンがMySQL/Sqliteだった場合、二つ目の引数は省略してもかまいません。
なるほど!
今回はMySQL
を使用するので、 2つ目の引数は省略して良いようです。
現在beedbはプリントデバッグをサポートしていますので、下のコードでデバッグを行うことができます。
beedb.OnDebug=true
これはONにしてみます。
以降の例では前のデータベースのテーブルUserinfoを採用します。まず目的のstructを作成します。
ORMのための、構造体を作成するようです。
type Userinfo struct {
Uid int `PK` //もしテーブルのプライマリキーがidでなければ、pkコメントを追加する必要があります。このフィールドがプライマリキーであることを明示します。
Username string
Departname string
Created time.Time
}
データの挿入
下のコードはどのように記録を挿入するか示しています。我々が操作しているのはstructオブジェクトで、元々のsql文ではありません。Saveインターフェースをコールしてデータをデータベースに保存します。
なるほど。
コード例もありますね。
早速全部試してみましょう。
まずは前回までに作成していたデータを削除しておきます。truncate userinfo;
beedb-insert.go
package main
import (
_ "github.com/go-sql-driver/mysql"
"database/sql"
"github.com/astaxie/beedb"
"time"
)
type Userinfo struct {
Uid int `PK` //もしテーブルのプライマリキーがidでなければ、pkコメントを追加する必要があります。このフィールドがプライマリキーであることを明示します。
Username string
Departname string
Created time.Time
}
func main() {
db, err := sql.Open("mysql", "root:root@tcp(mysql:3306)/gotest?charset=utf8")
checkErr(err)
defer db.Close()
orm := beedb.New(db)
// データの挿入
var saveone Userinfo
saveone.Username = "Test Add User"
saveone.Departname = "Test Add Departname"
saveone.Created = time.Now()
orm.Save(&saveone)
add := make(map[string]interface{})
add["username"] = "astaxie"
add["departname"] = "cloud develop"
add["created"] = "2012-12-02"
orm.SetTable("userinfo").Insert(add)
addslice := make([]map[string]interface{}, 0)
add1 := make(map[string]interface{})
add2:=make(map[string]interface{})
add1["username"] = "astaxie"
add1["departname"] = "cloud develop"
add1["created"] = "2012-12-02"
add2["username"] = "astaxie2"
add2["departname"] = "cloud develop2"
add2["created"] = "2012-12-02"
addslice =append(addslice, add, add2)
orm.SetTable("userinfo").InsertBatch(addslice)
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}
データが挿入できています!
上の操作方法はメソッドチェーンによる検索にすこし似ています。
jqueryに詳しい方はとても馴染みがあるのではないでしょうか。
毎回コールされるmethodはすべてもともとのormオブジェクトを返しているので、継続してオブジェクトの他のmethodをコールすることができます。
上でコールしたSetTable関数はORMに対して、これから実行するこのmapに対応したデータベーステーブルがuserinfoであると明示しています。
確かに!ORMは気持ちいいですね。
次は更新をしてみます。beedb-update.go
package main
import (
_ "github.com/go-sql-driver/mysql"
"database/sql"
"github.com/astaxie/beedb"
"time"
)
type Userinfo struct {
Uid int `PK` //もしテーブルのプライマリキーがidでなければ、pkコメントを追加する必要があります。このフィールドがプライマリキーであることを明示します。
Username string
Departname string
Created time.Time
}
func main() {
db, err := sql.Open("mysql", "root:root@tcp(mysql:3306)/gotest?charset=utf8")
checkErr(err)
defer db.Close()
orm := beedb.New(db)
// データの挿入
var saveone Userinfo
saveone.Username = "Update Username"
saveone.Departname = "Update Departname"
saveone.Created = time.Now()
orm.Save(&saveone) //現在saveoneにはプライマリキーがあります。更新操作を行います。
t := make(map[string]interface{})
t["username"] = "astaxie"
orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t)
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}
うーん、例のようにはうまく行っていないようです。
これは挿入後のオブジェクトを元に Save
をコールしているからPK
を保持しているという想定のようですね。
というわけで、今度は下記のようにしてみます。
beedb-update.go
package main
import (
_ "github.com/go-sql-driver/mysql"
"database/sql"
"github.com/astaxie/beedb"
"time"
)
type Userinfo struct {
Uid int `PK` //もしテーブルのプライマリキーがidでなければ、pkコメントを追加する必要があります。このフィールドがプライマリキーであることを明示します。
Username string
Departname string
Created time.Time
}
func main() {
db, err := sql.Open("mysql", "root:root@tcp(mysql:3306)/gotest?charset=utf8")
checkErr(err)
defer db.Close()
orm := beedb.New(db)
// データの挿入
var saveone Userinfo
saveone.Username = "Username"
saveone.Departname = "Departname"
saveone.Created = time.Now()
orm.Save(&saveone)
saveone.Username = "Updated! Username"
saveone.Departname = "Updated! Departname"
saveone.Created = time.Now()
orm.Save(&saveone) //現在saveoneにはプライマリキーがあります。更新操作を行います。
t := make(map[string]interface{})
t["username"] = "k-bushi!"
orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t)
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}
これで期待通りですね!
- 新しく挿入したものが更新されている。
- ID:2の名前が期待通りに更新されている。
さて次に行きましょう。
データの検索
package main
import (
_ "github.com/go-sql-driver/mysql"
"database/sql"
"github.com/astaxie/beedb"
"time"
"fmt"
)
type Userinfo struct {
Uid int `PK` //もしテーブルのプライマリキーがidでなければ、pkコメントを追加する必要があります。このフィールドがプライマリキーであることを明示します。
Username string
Departname string
Created time.Time
}
func main() {
db, err := sql.Open("mysql", "root:root@tcp(mysql:3306)/gotest?charset=utf8")
checkErr(err)
defer db.Close()
orm := beedb.New(db)
var user Userinfo
//Whereは2つの引数を受け取ります。int型の引数をサポートします。
orm.Where("uid=?", 1).Find(&user)
fmt.Println(user)
var user2 Userinfo
orm.Where(2).Find(&user2) // これは上の省略版です。プライマリキーは省略できます。
fmt.Println(user2)
var user3 Userinfo
//Whereは2つの引数を受け取ります。文字列型の引数をサポートします。
orm.Where("name = ?", "astaxie").Find(&user3)
fmt.Println(user3)
var user4 Userinfo
//Whereは3つの引数をサポートします。
orm.Where("name = ? and age < ?", "astaxie2", 88).Find(&user4)
fmt.Println(user4)
// 条件id>3にもとづいて、20からはじまる10件のデータを取得します。
var allusers []Userinfo
err = orm.Where("uid > ?", "1").Limit(10,20).FindAll(&allusers)
fmt.Println(allusers)
// 例2、limitの第二引数は省略できます。デフォルトは0から開始となります。10件のデータを取得します。
var tenusers []Userinfo
err = orm.Where("uid > ?", "1").Limit(10).FindAll(&tenusers)
fmt.Println(tenusers)
// 例3、すべてのデータを取得します。
var everyone []Userinfo
err = orm.OrderBy("uid desc,username asc").FindAll(&everyone)
fmt.Println(everyone)
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}
データの削除
こちらも同じように、
// 例1、単一のデータを削除
//saveoneは上の例で示したあのsaveoneです。
orm.Delete(&saveone)
// 例2、複数のデータを削除
//alluserは上で定義した複数のデータのsliceです。
orm.DeleteAll(&alluser)
// 例3、sqlにしたがってデータを削除
orm.SetTable("userinfo").Where("uid>?", 3).DeleteRow()
のような感じで削除できるようです!
おわりに
ORM開発は良さそうですね。
PHPの業務でやっているプロジェクトでORMなしで生SQLを投げまくるものがあるのですが、
配列がエグいことになってエグい(語彙力)
今日は疲れたので、記事が適当です。大変申し訳ございません。
もう少しだけ鞭(英語)を打って明日がんばります。