【Go】xormの使い方 その①(CRUD)

# はじめに

業務でxormを使ったのですが、参考にする記事が少なかった印象なので、
初学者への参考になればと記事にしてみました。
今回は基本的なCRUDのみです。

xormとは
Go言語で使えるORMです。
Go 1.6以降で利用可能です。

# 環境

go 1.15
github.com/go-sql-driver/mysql v1.6.0
xorm.io/xorm v1.2.3

# xormで出来ること

DBのテーブルと、Goの構造体のマッピングが出来ます。

このテーブルと
![スクリーンショット 2021-08-29 20.26.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986475/08b732d7-3fc7-4f8d-2e79-362fbf7bb8a5.png)
この構造体

```go
type User struct {
	Id       int64
	Name     string
	Age      int
	Password string    `xorm:"password"`
	Created  time.Time `xorm:"created"`
	Updated  time.Time `xorm:"updated"`
}
```
をマッピングします。
後で出てくるGetやFindのメソッドで構造体を指定するだけで勝手にマッピングしてくれます。
便利ですね。

xormのマッピングは先頭が大文字か小文字かは勝手に判断してくれて、いい具合にマッピングしてくれます。
構造体の「Id」は先頭が大文字ですが、DBのカラムは「id」と先頭小文字ですが、マッピングしてくれます。
ただ、構造体を「ID」とすると、マッピングされません。
うまいことやってくれるのは、先頭の文字だけです。

```
2021/08/29 22:54:28 Error 1075: Incorrect table definition; there can be only one auto column and it must be defined as a key
exit status 1
```

こんなエラーが出ます。
そういう構造体のフィールド名とDBのカラム名が違う場合は、xormタグで、カラム名を指定するとマッピングしてくれます。

```go
type User struct {
	ID       int64 `xorm:"id"`
}
```


# エンジンの作成

まず初めに、xormを使う為に、engineを作成します。
今回はmySQLを利用しています。
NewEngineの引数は人によって違うと思いますので、参考程度にご確認ください。
私はDockerで立てたsample_dbというDBを使用しています。

```go

func main() {
	engine, err := xorm.NewEngine("mysql", "root:root@tcp([127.0.0.1]:3306)/sample_db?charset=utf8mb4&parseTime=true")
	if err != nil {
		log.Fatal(err)
	}

	err = engine.Sync2(new(User))
	if err != nil {
		log.Fatal(err)
	}

}
```

# CRUD

CRUDのメソッドを説明していきます。

## Insert
CRUDでいうCREATEに当たるInsertです。

```go
// Insert
func Insert(engine xorm.Engine) {
	user := User{
		Name:     "太郎",
		Password: "パスワード",
		Age:      20,
	}
	_, err := engine.Table("user").Insert(user)
	if err != nil {
		log.Fatal(err)
	}
}
```

.Table(引数)でDBのテーブル名を指定します。
.Insertの引数にUser構造体を渡すと、User構造体で代入したName:太郎などが、DBに登録されます。

## Get

CRUDのREADです。
xormにはGetとFindがあり、
Getは単体取得(1レコードの取得)
Findは全件取得(複数レコードの取得)
です。

Insertと同じように、Getメソッドの引数に構造体を渡します。
User構造体をuserという名前で作成し、それをGetメソッドの引数に渡すことで、そのuserの中にDBのデータを取得する事が出来ます。
取得出来た場合は、返り値にboolでtrueが返ってきます。

```go
//Get 単体取得(1レコードを取得)
func Get(engine xorm.Engine) {
	user := User{}
	result, err := engine.Where("id = ?", 1).Get(&user)
	if err != nil {
		log.Fatal(err)
	}
	if !result {
		log.Fatal("Not Found")
	}
	fmt.Println("user:", user)
}
```

この上の例は
userテーブルから、idが1のレコードを習得しています。

出力結果

```
user: {1 太郎 20 パスワード 2021-08-29 16:32:18 +0900 JST 2021-08-29 17:48:14 +0900 JST}
```

## Find

Findは全件取得です。
複数のレコードが返ってくる為、構造体の配列を定義し、それをFindメソッドに引数として渡します。
この例では、ageが20歳のレコードを全件取得します。

```go
// Find 複数取得(複数レコードを取得)
func Find(engine xorm.Engine) {
	users := []User{}
	// ageが20のuserを全件取得します
	err := engine.Where("age = ?", 20).Find(&users)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("users:", users)
}
```

出力結果

```
users: [{1 太郎 20 パスワード 2021-08-29 16:32:18 +0900 JST 2021-08-29 17:48:14 +0900 JST} {6 花子 20 パスワード 2021-08-29 16:49:35 +0900 JST 2021-08-29 16:49:35 +0900 JST}]
```

## Count

Countはレコードの数を取得します。

```go
// Count レコードの数を取得
func Count(engine xorm.Engine) {
	user := User{}
	count, err := engine.Count(&user)
	if err != nil {
		log.Println(err)
	}
	fmt.Println("レコード数:", count)
}
```

出力結果

```
レコード数: 3
```

## Update

UpdateはDBのデータをUpdateします。
更新したいデータを構造体のフィールドに入力し、それをUpdateメソッドの引数に渡す事で、DBのレコードが書き変わります。
返り値に更新した数が返ってきます。
下記の例では、idが1のレコードを更新します。

```go
// Update
func Update(engine xorm.Engine) {
	user := User{
		Name:     "更新した名前",
		Password: "更新したパスワード",
		Age:      30,
	}
	result, err := engine.Where("id =?", 1).Update(&user)
	if err != nil {
		log.Println(err)
	}
	if result == 0 {
		log.Fatal("Not Found")
	}
	fmt.Println("user:", user)
}
```

出力結果

```
user: {0 更新した名前 30 更新したパスワード 0001-01-01 00:00:00 +0000 UTC 2021-08-29 23:52:06.220637 +0900 JST}
```

## Delete

最後はDeleteです。
下記の例ではidが1のレコードを削除します。
返り値に削除した数が返ってきます。

```go
// Delete
func Delete(engine xorm.Engine) {
	user := User{}
	result, err := engine.Where("id=?", 1).Delete(&user)
	if err != nil {
		log.Println(err)
	}
	if result == 0 {
		log.Fatal("Not Found")
	}
	fmt.Println("user:", user)
}
```

出力結果

```
user: {0  0  0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC}
```

# さいごに

xormもっと色々出来ますが、今回はこの辺にしておきます。
その②もよかったら見てください。


# 参考

https://pkg.go.dev/github.com/go-xorm/xorm