質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Q&A

解決済

1回答

1117閲覧

gormとgo-sqlite3の併用の仕方を教えてください!

退会済みユーザー

退会済みユーザー

総合スコア0

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

0グッド

0クリップ

投稿2017/09/10 16:14

編集2017/09/13 12:06

#まず
echoに関する質問3回目です。
いつもお世話になってます。

#やったこと
gormを少し触りました。
当方DBを扱ったことがないのでなんとなくですが。
gormのドキュメントを真似してファイルを作ることはできました。
以下該当コード
DB関係は別パッケージに切り出しました。
まずmain.goで関数を呼び出す部分

go

1e.GET("/api/register", func(c echo.Context) error { //アクセスするだけでいいため、とりあえずGETにしています 2 plugin.CreateDB() //下記で示す関数です 3 return c.Render(http.StatusOK, "index", nil) //特に何も返したくない場合何を書けばいいのかわからなかったので、適当に書きました 4 })

CreateDB関数(このような関数は実際には必要ないかと思われますが、テストなのでファイルを作るだけの関数を用意しました)

go

1type Product struct { //おそらくDBの形式を模した何か(?) 2 gorm.Model 3 Code string 4 Price uint 5} 6 7func CreateDB() { 8 db, err := gorm.Open("sqlite3", "test.db") //ファイル作成 9 if err != nil { 10 panic("failed to connect database") 11 } 12 defer db.Close() 13 db.Create(&Product{Code: "L1212", Price: 1000}) //先ほどの構造体を利用して書き込み 14}

このような感じです。

#質問

  • go-sqlite3はどのようにgormと併用すればいいのか
  • ドキュメントでは何故か_ "github.com/jinzhu/gorm/dialects/sqlite"がインポートされていたがそれはなんなのか

が知りたいです。
#ログインのサブミットに関して
サブミットの処理はhtmlで"/api/login"にpostするようにして、go側のe.POST()の中にDB関係の処理を書けばいいのかなと思っています。
なのでDBに関してを勉強しているというわけです。

#追記
・GORMのCreateについて
そもそも、GORMのCreateというのは、データベースのテーブルを作るという意味でしょうか?
つまり、

go

1db.Create(&Product{Code: "L1212", Price: 2000}) 2db.Create(&Product{Code: "L1213", Price: 3000}) 3db.Create(&Product{Code: "L1214", Price: 4000}) 4db.Create(&Product{Code: "L1215", Price: 5000}) 5db.Create(&Product{Code: "L1216", Price: 6000}) 6db.Create(&Product{Code: "L1217", Price: 7000})

このようなコードを実行すると、

CodePrice
L12122000
L12133000
L12144000
L12155000
L12166000
L12177000

こういったテーブルを作成するということでしょうか。

・マッピングとは
マッピングとは噛み砕くとどういう処理でしょうか?
ORM(オブジェクト関係マッピング)特有の用語なのかなというのはわかるのですが。。

go

1db.AutoMigrate(&Product{})

このコードはどういう場合(タイミング)に書くものなんでしょうか?

・Readについて

go

1var products []Product 2// Get all records 3db.Find(&products) 4//// SELECT * FROM products;

これはProductテーブル内の全てのレコードを取得するという意味かと思うのですが
セレクトしたものをプリントしようとして

go

1aa := db.Find(&products) 2fmt.Println(aa)

こう書いたのですが、

&{0xc420179280 <nil> 6 0xc420174dc0 false 0 {0xc4200fbf40} 0xc420418420 map[] 0xc42016f710 <nil> <nil> false}

このように出力されました。

これは、SELECTによって取得したものは、DBの操作でしか扱えない(型の問題上)ということなんでしょうか。

・go-sqlite3パッケージについて
mattnさんは回答において、go-sqlite3パッケージの関数等を直接使ってらっしゃらないと思うのですが、go-sqlite3はどこで使うのですか?
それとも、

go

1//db, err := gorm.Open("ドライバ名称", "接続文字列") 2db, err := gorm.Open("sqlite3", "foo.sqlite")

go-sqlite3はドライバという役割であって、GORMと併用する場合は直接使わないものなんですかね?

質問攻めすみません。

#追記2
とりあえず、gormを使ってDBにレコードを作ることはできるようになりました。
あとややこしく考えていましたが、GORMは、単純にGo言語でsqlを楽に扱うためのライブラリってことに気がついて気が楽になりました。

レコード作成はこうですね!↓(質問ではないので軽く見流していただければ結構です 汗)

go

1type UserData struct { 2 gorm.Model //ここにCreatedAtがあるのでタイムスタンプは任せればいいですね。 3 Userid string 4 Password string 5} 6 7func main() { 8 saveUserData("DDxlk", "DDxlkDayo") 9} 10 11func SaveUserData(userid, password string) { 12 db, err := gorm.Open("sqlite3", "test.sqlite3") 13 if err != nil { 14 panic("failed to connect database") 15 } 16 defer db.Close() 17 // Migrate the schema 18 db.AutoMigrate(&UserData{}) 19 // Create 20 user := &UserData{Userid: userid, Password: password} 21 db.Create(&user) 22}

###質問1
useridとpasswordをhtmlのフォームからechoに送ってdbに登録するわけですが、dbに何も書き込まれません(レコードのuseridとpasswordの部分が空白になってしまいます)
registration.html(登録)のフォームの部分が以下です

html

1<form action="/api/register" method="post" name="registration_form"> 2 <input type="text" name="userid" id="userid_form"/> 3 <input type="password" name="password" id="password_form"/> 4 <input type="hidden" name="register" value="register"> 5 <a id="login_button" onclick="document.registration_form.submit();return false;">Register</a> 6 </form>

そして、打ち込まれたuseridとpasswordをdbに登録する処理が以下です

go

1//echo 2e.POST("/api/register", func(c echo.Context) error { 3 id := c.Param("userid") //フォームからidを取得しているつもり 4 password := c.Param("password") //フォームからpasswordを取得しているつもり 5 SaveIdOnDB(id, password) 6 return c.Render(http.StatusOK, "index", nil) 7)} 8 9type UserData struct { 10 gorm.Model 11 Userid string 12 Password string 13} 14 15func SaveUserData(userid, password string) { 16 db, err := gorm.Open("sqlite3", "test.sqlite3") 17 if err != nil { 18 panic("failed to connect database") 19 } 20 defer db.Close() 21 // Migrate the schema 22 db.AutoMigrate(&UserData{}) 23 // Create 24 user := &UserData{Userid: userid, Password: password} 25 db.Create(&user)

###質問2
先ほどからtest.sqlite3の中にレコードを作成してるわけなんですが、レコードの値をコマンドラインに出力するにはどうすればいいのでしょうか。(先日コメントでも申し上げた通り、fmt.Printlnするとポインタの値が出力されます)

今はそれがわからないため、DB Browser for SQLiteというGUIソフトで中身を閲覧しています。
DB Browser for SQLite

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

go-sqlite3はどのようにgormと併用すればいいのか

gorm の使い方は

  • 接続: ファイル形式、URI 形式
  • マッピング: テーブルと struct のマッピング
  • 検索: First や Last、Find 等を使った単一行検索、Find を使った複数行検索
  • 操作: NewRecord や Create を使った挿入、Update を使った更新、Delete を使った削除

が標準的な使い方です。

接続

go

1db, err := gorm.Open("ドライバ名称", "接続文字列")

ドライバ名称、接続文字列は各ドライバで異なります。go-sqlite3 であれば

go

1db, err := gorm.Open("sqlite3", "foo.sqlite")

という db ファイルのパスを指定する事も出来ますし、URI 形式でも接続出来ます。

https://sqlite.org/uri.html

マッピング

go

1type Product struct { //おそらくDBの形式を模した何か(?) 2 gorm.Model 3 Code string 4 Price uint 5}

この形式は、gorm.Model を内包する形式です。こう書く事で実際は以下の struct メンバも内包される事になります。

type Model struct { ID uint `gorm:"primary_key"` CreatedAt time.Time UpdatedAt time.Time DeletedAt *time.Time }

gorm を使われるならば、このままで良いと思います。この CreatedAt や UpdatedAt、DeletedAt は DB 操作である Create や Delete、Update 等を使えば自動で更新されます。また ID も Find 等で利用される為、開発者は ID をそれほど意識しなくても良くなります。

マッピングは AutoMigrate を呼び出すだけです。

go

1db.AutoMigrate(&Product{})

使われるテーブルを全てここでマッピングして下さい。gorm はなかなか優秀で、マッピングだけでなくマイグレートも行ってくれます。開発途中で struct フィールドを増やしてもある程度は gorm が修正してくれます。ただし、あまりに大きい修正は追従してくれませんので、大きな変更をする際には DB ファイルをバックアップしていた方が良いです。

なお、gorm 等の様に ORM を使う場合、Create Table すらも ORM に任せるのが一般的ですが、テーブルのフィールドに gorm: のプレフィックスタグを付ける事で既存の DDL を使ったテーブル操作も出来ます。

検索

http://jinzhu.me/gorm/crud.html#query

go

1db.First(&product) 2//// SELECT * FROM products ORDER BY id LIMIT 1; 3 4db.Last(&product) 5//// SELECT * FROM products ORDER BY id DESC LIMIT 1; 6 7db.Find(&products) 8//// SELECT * FROM products; 9 10db.First(&product, 10)

検索の基本形式です。product は

go

1var product Product

で宣言した変数を渡し、projects は

go

1var products []Product

で宣言した変数を渡して下さい。

操作

http://jinzhu.me/gorm/crud.html

このページにおおよそ書かれています。ID に値を入れずに Create を呼び出して下さい。フィールドの値を変更して Update を実行すれば更新、ID 付きの物を Delete すれば削除になります。

ドキュメントでは何故か_ "github.com/jinzhu/gorm/dialects/sqlite"がインポートされていたがそれはなんなのか

これは、このプログラムが sqlite3 のデータベースを使いますよというおまじないです。golang ではインポートするけど参照しない物は _ で名付けします。なんとなく、github.com/mattn/go-sqlite をインポートすれば良い気がするかもしれませんが、gorm の様な ORM は、各 DBMS の SQL 方言を吸収する必要がありますよね。そこで各ドライバ毎に dialect (方言) を設定するのです。
sqlite には方言がないので処理が書かれていませんが、postgres のドライバは幾らか方言用の処理が書かれています。

https://github.com/jinzhu/gorm/blob/master/dialects/postgres/postgres.go

sqlite3 だけでなく他のデータベースにもつなげたいならば、使う分 import する必要があります。

go

1import _ "github.com/jinzhu/gorm/dialects/mysql" 2// import _ "github.com/jinzhu/gorm/dialects/postgres" 3// import _ "github.com/jinzhu/gorm/dialects/sqlite" 4// import _ "github.com/jinzhu/gorm/dialects/mssql"

#追記2について

以下のコードで test.sqlite3 にレコードが追加されている(foo/barも入っている)事は確認出来ています。
DB Browser for SQLite のリロードボタンなどで最新が表示されないでしょうか。

go

1package main 2 3import ( 4 "github.com/jinzhu/gorm" 5 _ "github.com/jinzhu/gorm/dialects/sqlite" 6) 7 8type UserData struct { 9 gorm.Model 10 Userid string 11 Password string 12} 13 14func main() { 15 db, err := gorm.Open("sqlite3", "test.sqlite3") 16 if err != nil { 17 panic("failed to connect database: " + err.Error()) 18 } 19 defer db.Close() 20 // Migrate the schema 21 db.AutoMigrate(&UserData{}) 22 // Create 23 user := &UserData{Userid: "foo", Password: "bar"} 24 db.Create(&user) 25}

投稿2017/09/11 00:13

編集2017/09/14 04:34
mattn

総合スコア5030

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/09/11 10:28

いつも回答ありがとうございます。 DB、ひいてはgormに関して少〜しずつ理解出来て参りました。 さらに回答を読ませていただいた上で疑問に感じたことを追記させていただきました。 よろしくお願いしますm(_ _)m
mattn

2017/09/11 11:09 編集

> そもそも、GORMのCreateというのは、データベースのテーブルを作るという意味でしょうか? いえ、レコードを作る関数です。プライマリキーを指定せずに NewRecord を呼び出すと、新規レコードかどうかを true/false で返すので true の場合に Create、false の場合に Update する事になります。 なおテーブルを作るのは `db.CreateTable(&Product{})` です。 > マッピングとは噛み砕くとどういう処理でしょうか? テーブルのスキーマと struct と付け合せを行います。形があっているか、あってないのか、あってないなら alter table する、といった事をやっています。DB 接続を得た後、また Create や Find 等を呼ぶ前、に呼び出します。 >これは、SELECTによって取得したものは、DBの操作でしか扱えない(型の問題上)ということなんでしょうか。 ここは DB や gorm に関係ない話で、単に fmt.Println が構造体ポインタを表示しているだけです。Product に String() という文字列を返すメソッドを追加すると中身を(自分で)表示する事が出来ます。なお、fmt.Sprintf や fmt.Fprintf/fmt.Printf の書式部に %+v を渡すと中身を展開してくれます。 https://play.golang.org/p/m7DmtKE6qK > go-sqlite3 について import _ "github.com/jinzhu/gorm/dialects/sqlite" という行を書かれておられると思いますが、このパッケージの中で go-sqlite3 をインポートしてくれています。 https://github.com/jinzhu/gorm/blob/master/dialects/sqlite/sqlite.go なぜ github.com/jinzhu/gorm/dialects/sqlite をインポートする必要があるのかについては↑に書いてある通りです。
退会済みユーザー

退会済みユーザー

2017/09/11 14:25

なるほど、ありがとうございます おおお、"github.com/jinzhu/gorm/dialects/sqlite"ここの中にgo-sqlite3が組み込まれてたんですね!
退会済みユーザー

退会済みユーザー

2017/09/11 15:07 編集

データベースが初めてということで混乱して出力などという変なことしてましたね a := db.First(&product) でDB型を取得して、a.method()やhoge.method(a)等で進めるんですね。w 意味不明な質問をしてしまい、すみませんでした
mattn

2017/09/11 15:26

gorm ではクエリをメソッドチェインで作成できるというのはお気づきの通りです。 db.Model(&Product{}).Where("foo = ?", 3).Pluck("bar", &bar) db.Model(&Product{}).Where({Foo: 3}).Pluck("bar", &bar) ただし First や Find は最後に値を取得する関数なので First/Find に続く物は Error など、抽出後のメソッドやフィールドになりますね。
退会済みユーザー

退会済みユーザー

2017/09/13 11:47

長らくお待たせしました。 すこし忙しかったため遅れました とりあえずなんとなく把握できました。 あと二つだけ聞きたいことがあるので、追記させていただこうと思います。 とりあえずそれでこの質問はmattnさんをBAとして区切りますので、あと少しばかりお付き合いくださいm(_ _)m
退会済みユーザー

退会済みユーザー

2017/09/14 07:54 編集

追記ありがとうございます。 私の追記2にも書かせて頂いてますが、単純なレコードのCreateに関しては出来るんです。 ただ、echoを経由してhtmlのフォームから読み取る方法が上手くできません。(私のコードではc.Param("nameアトリビュート")を使って取得しようとしている)
mattn

2017/09/14 08:11 編集

Param は URL パラメータを取る物です。POST データを取る場合は ctx.FormValue(name) を使って下さい。
退会済みユーザー

退会済みユーザー

2017/09/14 08:46

うまくできました! ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問