LoginSignup
7
6

More than 5 years have passed since last update.

Go言語のgormでORMしてみた(単純CUD編)

Last updated at Posted at 2016-08-15

前提

  • Go言語そのものに慣れていない
  • MySQLはVagrantで適当にCentOS6.6に構築
  • 単純検索ぐらいはできるようになった

今回のTODO

  • 登録・更新・削除できるようになる
  • トランザクション制御ができるようになる
  • 登録時のPKを取得する

いざ実践!

問題点

  • 登録時のPKを取得数方法がわからない
    • tx.Create の戻り値の中に Value があるが、interface{} でリフレクションしたくない

解決策

  • 検索結果をstructに変換するメソッドで解決できた
db_connection2.go
// DBアクセスsample2.go
package main

import (
    "fmt"

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

type User struct {
    ID    uint64 `gorm:"primary_key"`
    Email string `gorm:"type:varchar(255);"`
    Name  string `gorm:"type:varchar(45);"`
}

func main() {
    db, err := gorm.Open("mysql", "testuser:testuser@/go_sample?charset=utf8&parseTime=True&loc=Local")
    if err != nil {
        panic("failed to connect database")
    }
    // テーブル名が複数系でない場合、これを指定すること
    db.SingularTable(true)

    // 実行ログ出力
    //  db.LogMode(true)

    // 最新のIDを取得してインサートすると見せかけてロールバックする
    var user User
    var id uint64 = lastPrint(db, user)

    tx := db.Begin()

    var sid = fmt.Sprint(id)
    user = User{Email: "sample@" + sid + "test.com", Name: "Name" + sid}
    savePrint(tx, user)

    tx.Rollback()

    // 更新されていないことを確認
    lastPrint(db, user)

    tx = db.Begin()
    id, err = savePrint(tx, user)
    // 本来はエラーならロールバック
    tx.Commit()

    // 更新されていることを確認
    lastPrint(db, user)

    // 更新メソッドが実行されることを確認
    tx = db.Begin()
    user.ID = id
    savePrint(tx, user)
    tx.Commit()

    // レコードが追加されていないことを確認
    lastPrint(db, user)

    // 削除されることを確認
    tx = db.Begin()
    tx.Delete(user)
    tx.Commit()

    // 削除されていることを確認
    user.ID = uint64(0)
    lastPrint(db, user)
}

func lastPrint(db *gorm.DB, user User) uint64 {
    var count int
    db.Last(&user).Count(&count)
    if count == 0 {
        fmt.Println("該当レコードなし")
    } else {
        fmt.Println("id:" + fmt.Sprint(user.ID))
    }
    return user.ID
}

// 本当は Save を使えば事足りるはず
func savePrint(tx *gorm.DB, user User) (uint64, error) {
    // 戻り値用の変数定義
    var rId uint64 = 0

    // PKを設定しないと true を返すらしい
    if tx.NewRecord(user) {
        fmt.Println("\t新規レコードです。")
        result := tx.Create(&user)
        if result.Error != nil {
            return rId, result.Error
        }

        // 追加したIDが欲しい場合、Scanで元の形に変換する
        result.Scan(&user)
        sid := fmt.Sprint(user.ID)
        fmt.Println("\t新規追加したID:" + sid)
        rId = user.ID
    } else {
        fmt.Println("\t更新レコードです。")
        rId = user.ID
        result := tx.Model(&user).Update(&user)
        if result.Error != nil {
            return rId, result.Error
        }
        sid := fmt.Sprint(user.ID)
        fmt.Println("\t更新したID:" + sid)
    }
    return rId, nil
}

残課題

  • 件数をわざわざ取得しないで存在しないチェックを行いたい
    • ID == 0 でも良いけれど、美しくない
  • 検索条件の初期化の際に ID = 0 以外の方法を探す

TODO

  • 複雑な検索結果の取得
  • リレーションの貼り方、概念的な整理
  • ソースの自動生成
7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6