gin gormでテーブル操作（少し改良版）


以前[gin gormでテーブル操作](https://qiita.com/ogurasousui/items/dcd84fd96d2e8797a5e8)で一連のテーブル操作をやってみた

しかし、どうもBDのコネクションは保持したままの方が良いようなので、修正してみる
ついでに[こちら](https://qiita.com/ogurasousui/items/b7a49d78615c7c97b911)と同じGo Modules管理に変更している

以下雑にコードをのせているだけなので、何が変わったかは↑の記事と見比べてください（すまん

## docker-compose.yml

```docker-compose.yml
services:
  app:
    container_name: gin_app
    image: golang:1.12.0-alpine
    volumes:
      - .:/go/src/app
    command: >
      sh -c "cd /go/src/app &&
      apk update &&
      apk add --no-cache git &&
      GO111MODULE=off go get -u github.com/codegangsta/gin &&
      go mod init || : &&
      gin -i run"
    ports:
      - 3001:3001
    environment:
      GO111MODULE: "on"
```

## DB

```db/db.go
package db

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

var database *gorm.DB

func Connection() *gorm.DB {
	var err error
	database, err = gorm.Open("mysql", "root:@tcp(db:3306)/gin_app?charset=utf8&parseTime=True&loc=Local")
	if err != nil {
		panic("failed to connect database")
	}
	database.LogMode(true)
	return database
}

func DB() *gorm.DB {
	return database
}

```

毎回接続せずにコネクションを変数に保持する形式に変更。他packageでは `db.DB()` で取得できるようにしている

## マイグレーション

こちらもメソッドに。任意で実行できるように変更 

```migrate/migrate.go
package main

import (
	"app/db"
	"app/model"

	_ "github.com/jinzhu/gorm/dialects/mysql"
)

func main() {
	db.Connection()
	defer db.DB().Close()

	db.DB().AutoMigrate(&model.User{})
	db.DB().AutoMigrate(&model.UserName{})
}
```

マイグレーション実行
Go Modules管理に変更したら以前の方法だとエラーになるので少し修正

```
$ docker exec -it gin_app sh -c "cd /go/src/app; go run migrate/migrate.go"
```

## モデル

ここは変更なし

```model/user.go
package model

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

type User struct {
	gorm.Model
	UserName UserName
}
```

```model/user_name.go
package model

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

type UserName struct {
	gorm.Model
	UserID uint
	Name   string
}
```

## コントローラ
DBの取得方法を変更

```controller/user.go
package controller

import (
	"app/db"
	"app/model"

	"github.com/gin-gonic/gin"
)

type User struct{}

func NewUser() *User {
	return &User{}
}

func (t *User) Get(c *gin.Context) {
	db := db.DB()

	var user model.User
	result := db.First(&user, c.Param("id")).Related(&user.UserName)
	c.JSON(200, result.Value)
}

func (t *User) List(c *gin.Context) {
	db := db.DB()

	var users []model.User
	result := db.Preload("UserName").Find(&users)
	c.JSON(200, result.Value)
}

func (t *User) Create(c *gin.Context) {
	db := db.DB()

	var user model.User
	db.Create(&user)

	var userName model.UserName
	c.BindJSON(&userName)
	userName.UserID = user.ID
	db.Create(&userName)
}

func (t *User) Update(c *gin.Context) {
	db := db.DB()

	var user model.User
	db.First(&user, c.Param("id")).Related(&user.UserName)
	if user.UserName.ID > 0 {
		c.BindJSON(&user.UserName)
		db.Save(&user.UserName)
	}
}

func (t *User) Delete(c *gin.Context) {
	db := db.DB()

	var user model.User
	db.First(&user, c.Param("id")).Related(&user.UserName)
	if user.ID > 0 {
		db.Delete(&user)
	}
	if user.UserName.ID > 0 {
		db.Delete(&user.UserName)
	}

	// こっちの消し方でも良い
	// db.Where("id = ?", c.Param("id")).Delete(&model.User{})
	// db.Where("user_id = ?", c.Param("id")).Delete(&model.UserName{})
}
```
## main
はじめにDB接続をするように変更

```main.go
package main

import (
	"app/controller"

	"github.com/gin-gonic/gin"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

func main() {
	db.Connection()
	defer db.DB().Close()

	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.GET("/users", controller.NewUser().List)
	r.GET("/users/:id", controller.NewUser().Get)
	r.POST("/users", controller.NewUser().Create)
	r.PUT("/users/:id", controller.NewUser().Update)
	r.DELETE("/users/:id", controller.NewUser().Delete)

	r.Run()
}
```