Slick+PlayFramework2でデータベースアクセス

ScalaでPlayFrameworkを使う場合にDBアクセスにはanormとslickがあるようです。

slickはscalaQueryと呼ばれていたものが進化した模様。

scala2.9まではscalaQuery,それ以降はslickらしいです

http://d.hatena.ne.jp/tototoshi/20121204/1354615421

Build.scalaに必要なモジュールを書いてインストールするのが一般的らしいですが、うまくいかなかったので手動インストールで作成してみます。

slick

https://github.com/freekh/play-slick

からZIPでダウンロードし解凍

 $ cd slick-1.0.1
 $ sbt
 > compile
 > package
 $ find .|grep jar
	./slick-testkit/target/scala-2.10/slick-testkit_2.10-1.0.1.jar
	./target/root/scala-2.10/root_2.10-1.0.1.jar
	./target/scala-2.10/slick_2.10-1.0.1.jar

play-slick

プラグインなのでこちらも入れます

https://github.com/freekh/play-slick

 $ cd play-slick-master
 $ sbt
 > compile
 > package
 $ find .|grep jar
 ./target/scala-2.10/play-slick_2.10-0.3.3-SNAPSHOT.jar

プロジェクト作成

$ play new sample
			 _						_
 _ __ | | __ _ _	_| |
| '_ \| |/ _' | || |_|
|	__/|_|\____|\__ (_)
|_|						|__/

play! 2.1.2 (using Java 1.7.0_25 and Scala 2.10.0), http://www.playframework.org

The new application will be created in /Users/admin/Documents/workspace/play_sample/sample

What is the application name? [sample]
> sample

Which template do you want to use for this new application? 

	1						 - Create a simple Scala application
	2						 - Create a simple Java application

> 1
OK, application sample is created.

Have fun!

$ cd sample
$ play eclipse
$ mkdir lib
$ cp slick-1.0.1/target/scala-2.10/slick_2.10-1.0.1.jar .
$ cp play-slick-master/target/scala-2.10/play-slick_2.10-0.3.3-SNAPSHOT.jar .

Eclipse

  • eclipseの既存プロジェクトの読み込みで読み込む
  • プロジェクトのプロパティからslick_2.10-1.0.1.jar、play-slick_2.10-0.3.3-SNAPSHOT.jarのライブラリを追加

PlayFramework

http://takashima0411.hatenablog.com/entry/2012/11/28/231817

こちらの方のサンプルをそのままいただきました

Application.scala
package controllers

import play.api._
import play.api.mvc._

import play.api.data._
import play.api.data.Forms._

import models._

object Application extends Controller {

	val taskForm = Form(
		"label" -> nonEmptyText)

	def index = Action {
		Redirect(routes.Application.tasks)
	}

	def tasks = Action {
		Ok(views.html.index(Tasks.all(), taskForm))
	}

	def newTask = Action { implicit request =>
		taskForm.bindFromRequest.fold(
			errors => BadRequest(views.html.index(Tasks.all(), errors)),
			label => {
				Tasks.create(label)
				Redirect(routes.Application.tasks)
			})
	}

	def deleteTask(id: Long) = Action {
		Tasks.delete(id)
		Redirect(routes.Application.tasks)
	}

}
Task.scala
package models

import scala.slick.driver.H2Driver.simple._
import Database.threadLocalSession

case class Task(id: Long, label: String)

object Tasks extends Table[Task]("TASK") {

	def id = column[Long]("ID", O.PrimaryKey, O.AutoInc)
	def label = column[String]("LABEL", O.NotNull)
	def * = id ~ label <> (Task, Task.unapply _)
	def ins = label returning id

	def all(): List[Task] = connectDB {
		Query(Tasks).sortBy(_.id).list
	}

	def create(label: String) = connectDB {
		Tasks.ins.insert(label)
	}

	def delete(id: Long) = connectDB {
		Tasks.where(_.id === id).delete
	}

	def connectDB[Any](f: => Any): Any = {
		Database.forURL("jdbc:h2:mem:play", driver = "org.h2.Driver") withSession {
			f
		}
	}

}
Global.scala
import play.api._
import models._
import scala.slick.driver.H2Driver.simple._
import Database.threadLocalSession

import models._
import java.sql.{Date,Time,Timestamp}

object Global extends GlobalSettings {

	override def onStart(app: Application) {
		Logger.info("Application has started")

		Database.forURL("jdbc:h2:mem:play", driver = "org.h2.Driver") withSession {

			Tasks.ddl.create

		}

	}

	override def onStop(app: Application) {
		Logger.info("Application shutdown...")
	}

}
index.scala.html

@(tasks: List[Task], taskForm: Form[String])

@import helper._


		
		

@tasks.size task(s)

    @tasks.map { task =>
  • @task.label @form(routes.Application.deleteTask(task.id)) { }
  • }

Add a new task

@form(routes.Application.newTask) { @inputText(taskForm("label")) }
routes
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~

# Home page
GET		 /													 controllers.Application.index
GET		 /index											controllers.Application.index
GET		 /tasks											controllers.Application.tasks
GET		 /newTask										controllers.Application.newTask
GET		 /deleteTask/:id								 controllers.Application.deleteTask(id:Long)

# Map static resources from the /public folder to the /assets URL path
GET		 /assets/*file							 controllers.Assets.at(path="/public", file)
application.conf
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"


slick.default="models.*"

# Evolutions
# ~~~~~
# You can disable evolutions if needed
evolutionplugin=disabled

これでとりあえず動きます