Squerylで簡単なDBの操作をやってみた

今回はDBの操作(Select,Insert,Update,Delete)をSquerylを使って行ったのでメモ。

まず今回はDBの操作だけを目的としているため、フォームなどは使わずにあるページにアクセスしたらDBにある操作が実行されるという形式で行いました。
例えば、localhost:9000/indexというページを表示するとpostテーブルにinsert文が実行されるといった感じです。

また参考にしたページは↓です。
Select - Squeryl - A Scala ORM for SQL Databases
Insert, Update and Delete - Squeryl - A Scala ORM for SQL Databases

SQL文を実行する前に↓をimportする

import models._
import org.squeryl.PrimitiveTypeMode._

ではまだデータがない状態なのでInsertから。

  transaction {
    schema_name.insert(new model_name(column1, column2))
  }

これでDBに値が入っていたらOK

あとここで記述されているtransactionは一般的なトランザクションとほぼ同義です。
→transactionはブロック内でトランザクションを開始し、ブロックが終了するとコミットする。(ブロック内でもし例外が発生するとロールバックする)
引用:SquerylのSessionとTransaction - Develop with pleasure!


次はUpdateです。

//update
  transaction {
    update(schema_name)(p =>
      where(p.id === 1)
      set(p.column1:= "Hello Squeryl !!")
  }

SQLがわかれば、大体なにをやっているかはわかりますよね。

今度はDeleteを見ていきます。
今回はidは決め打ちで。

//delete
  transaction {
      schema_name.deleteWhere(sch => sch.id === 1)
  }

最後にSelectですがちょっと引っ掛け!?
自分だけなんでしょうか。

//select
  transaction {
      from(schema)(s => where(sch.id === 1) select(sch))
  }

これだけではselect文は実行されません。(定義したのみの状態)
参考にしていたページにはそれ以上のことは書いていない(探せないだけ?)。
select文を実行するためには、toListやheadOptionをつけてあげたらいいとのこと。

こんな感じ↓

//select
  transaction {
    val sql = from(schema)(s => where(sch.id === 1) select(sch)).headOption
    //ちゃんと実行できているかlogに出力
    Logger.debug(sql.toString)
  }

これでできるようになりました。
ログにもちゃんと出力されるようになりました↓

[info] play - database [default] connected at jdbc:postgresql://~
[info] play - Application started (Dev)
[debug] application - List(Post(hello world,今日は快晴です!!))

*ログの出力方法については別途記事作成します。

以上Squerylを使った簡単なDB操作にでした。

追記

transactionとinTransactionの違い

・transactionはブロック内でトランザクションを開始し、ブロックが終了するとコミットする。
トランザクションを実行する際は、例え既存のトランザクションコンテキスト内で呼ばれたとしても、いつも新規にトランザクションが生成される。

・inTransaction
inTransactionは実行中のトランザクションが無い場合に新規にトランザクションを生成する。既にトランザクションが存在する場合はそのトランザクションコンテキストが利用される。

この両者の使い分けって妨げられたくない処理がある時は、transactionを使えってことでいいのかな!?

Active Recordパターン

Active RecordっぽくDBの操作もできるようなので、その方法も書いてみます。
尚今回の使うpostのスキーマ定義は↓のようになっています。

package db {

import org.squeryl.{Schema, KeyedEntity}

    case class Post(
        title: String,
        content: String) extends KeyedEntity[Long] {
            val id: Long = 0
    }

    object AppDB extends Schema {
      val postTable = table[Post]("post")
    }
}
//schemaオブジェクトのコンテンツをimport
//dbパッケージのimportではないことに注意(汗)
  import AppDB._

  transaction {
    new Post("Hello Scala", "scala scala").save
  }

updateも試しましたが苦労しました。
最初にDBからupdateしたいフィールドをとってくる必要があるって当たり前のことに気づかず。。。
updateはこんな感じで行います。

  import AppDB._

    transaction {
//selectでテーブルから情報取ってきてる
//今回は該当idがあることが前提なのでgetメソッド使用
      val helloScala = from(AppDB.postTable)(p => 
         where(p.id === 12) select(p)).headOption.get
//copyメソッドでタイトルだけ違うインスタンス生成
      val updatePost = helloScala.copy(title = "Hello !! Scala !!")
//update処理
      updatePost.update

ちなみに上ではgetメソッドを使用していますが、値が確実に返ってくるか分からない場合は下のようにmapを使います。

//idがあるかどうか分からない場合はmapを使って書いた方が良い
      from(AppDB.postTable)(p => 
        where(p.id === 12) select(p)).headOption.map{ post => 
          val newPost = post.copy(title = "Hello !! Scala !!")
          newPost.update
        }.getOrElse(/*Noneの場合の処理*/)

getメソッドを使った場合だと、値がNoneの場合errorになります。
↑の場合だとNoneのときはgetOrElseのあとの処理が返されます。

また下のリンクページにも書いているのですが、Entityに部分はこのように変更しないとupdateできません。
変更前だとidが常に0になるためです。insertの場合はそのままでOKなのですがupdateの場合はid=0では正常に動作しません。当たり前ですが。。。該当idをちゃんと渡せるようにするためには下のように変更してください。

 //変更前
    case class Post(
      title: String,
      content: String) extends KeyedEntity[Long] {
        val id: Long = 0

    }

//変更後
    case class Post(
      id: Long,
      title: String,
      content: String) extends KeyedEntity[Long] {
    }

Play2.3でCRUDを使った一覧ページの作成してみる - hikonori07’s blog


もっと複雑なsql文を書きたいという人は最初にも説明しましたが、
Select - Squeryl - A Scala ORM for SQL Databases
Insert, Update and Delete - Squeryl - A Scala ORM for SQL Databases
これらのページを参考ください。当たり前ですがselectはさらに色んなバリエーションがありますね。


Scalaスケーラブルプログラミング第2版

Scalaスケーラブルプログラミング第2版

Guide to ScalaーScalaプログラミング入門

Guide to ScalaーScalaプログラミング入門

Scala逆引きレシピ (PROGRAMMER’S RECiPE)

Scala逆引きレシピ (PROGRAMMER’S RECiPE)