Hatena::ブログ(Diary)

すにぺっと

2011-04-22

play-scalaを改めて学ぶ-8 DBアクセス

| 22:18 | play-scalaを改めて学ぶ-8 DBアクセス - すにぺっと を含むブックマーク

今日は

http://scala.playframework.org/documentation/scala-0.9/database

を学ぶ。

Database access options

ほとんどのアプリケーションデータベースアクセスを伴う。

ここではplay-scalaアプリケーションデータベースを管理する

オプションについて説明する。


Using Anorm

Scalaモジュールは、DBへのリクエストと解析のAPIを提供し

結果のデータセットを変換するためのシンプルなSQLでのアクセスを行う

Anormと呼ばれる新しいデータアクセス層を含む。

我々は、それがScalaからRDBにアクセスするためにpalyとScalaの完全に統合された最善の方法であると信じている。

詳細については、完全なマニュアルを確認。

この新しく追加されてAnormってのはかなりいいみたい。
別途詳細に説明されてる。

Using JPA

JPAHibernateインプリメンテーション)は、PlayアプリケーションにおいてRDBにアクセスする標準の方法。

これはplay-Scalaアプリケーションから使用することはまだ可能だが、

すでに最良の方法ではなく、非推奨である。


ScalaJPAを使うにはいくつか問題点がある。

JPAは、エンティティとのリレーション設定にはJavaのコレクションライブラリを使用する。

 もちろん、Scalaの暗黙の型変換でJavaの型へ変換できるが、理想的な方法ではない。

・いくつかのDBカラムはnullを許容する。

 ベテランScala使いはmapをOption型で使いたいだろうが、これは不可能。

JPAは、Javaアノテーションの多くに依存している。

 実際にJavaScalaアノテーションには互換性でいくつかの違いがある。

しかし、最も重要な点は、「関数型言語の力を使用するために、ORマッパーへの関連は必要があるか?」ということ。

JPAでは、Javaの型へ変換するには便利な方法だが、Scalaを使い始めると間違っていると感じるだろう。

ORマップはScalaのOptionとか関数型プログラミングと
相性悪いということか。

とりあえず、play-ScalaアプリケーションからJPAを使用する場合、

コンパニオンオブジェクトを使用してplay.db.jpa.Modelクラスを定義する。

import play.db.jpa._
 
import java.util.{List -> JList}
import javax.persistence._
 
@Entity class User extends Model {
    
    var name:String
    var email:String
    
    @OneToMany var posts:JList[Post]
    
}
 
object User extends QueryOn[User]

Userクラスとコンパニオンオブジェクトに注意。

重要なポイントは、

・case classではなく通常のclassでていぎすること。

・空のコンストラクタを用意しておくこと。

・常にコンストラクタではなく、フィールドにJPAアノテーションを定義すること。

・フィールドは可変なので、valではなくvarを使用。

・エンティティの関連を示すには、java.util.Collection APIを使用。

・エンティティクラスには findやその他のファクトリメソッドは持ってはいけない。

 そのためには、QueryOn[T]トレイトをmix-inするコンパニオンオブジェクトを作成する。

 そして、これがエンティティにアクセスするためにQueryOn[T]のAPIを使用している例。

val mayBeUser:Option[User] = User.findById(5)
val totoUsers:List[User] = User.find("byName", "Toto").fetch()
User.all().fetch().each { _.delete() }

Integrating other existing Database access librairies

おそらく、あなたはすでにScalaの別の既存DBアクセスライブラリを使用して、

playアプリケーションからそれを使用しているだろう。基本的にplayアプリケーションではJDBC接続を管理し、

必要に応じてその他既存のフレームワークを統合するために使用できる、

単純なjava.sql.Connectionを使用するアプリケーションを提供する。


例えば、これは ScalaQueryをplayアプリケーションに統合する方法。

1. dependencies.yml ファイルにScalaQueryを追加

ScalaQueryはScala Toolsリポジトリから入手可能。

まず、アプリケーションのconf/ depenencies.ymlファイルを開き、以下の内容を追加する。

# Application dependencies
 
require:
    - play
    - play -> scala 0.9
    - org.scalaquery -> scalaquery_2.8.1 0.9.1:
        transitive:     false
    
repositories:
    
    - Scala Tools:
        type:       iBiblio
        root:       http://scala-tools.org/repo-releases
        contains:   
            - org.scalaquery -> *

でもって コマンド実行:

$ play dependencies

必要なjarインストールする。


2. アプリケーションのデータソース設定

アプリケーションのconf/application.confファイルで、memory database部分の

コメントをはずして有効化。

# To quickly set up a development database, use either:
#   - mem : for a transient in memory database (H2 in memory)
#   - fs  : for a simple file written database (H2 file stored)
db=mem

3. DB初期化スクリプトを実行

db/evolutionsディレクトリを作成し、

まだ作成していなければ1.sqlという名前で作成する。

# Users schema
 
# --- !Ups
 
CREATE TABLE MEMBERS (
    ID bigint(20) NOT NULL,
    NAME varchar(255) NOT NULL,
    EMAIL varchar(255),
    PRIMARY KEY (ID)
);
 
INSERT INTO members VALUES (1, 'Guillaume', 'gbo@zenexity.com');
INSERT INTO members VALUES (2, 'Sadek', NULL);
 
# --- !Downs
 
DROP TABLE MEMBERS;

このスクリプトはインメモリデータベースを実行されており、

データベースが空なので自動的に適用される。

ログを確認すると下記のようになっている。

…
13:31:50,674 INFO  ~ Connected to jdbc:h2:mem:play;MODE=MYSQL
13:31:50,752 INFO  ~ Application 'myScalaQueryApp' is now started !
13:31:51,064 INFO  ~ Automatically applying evolutions in in-memory database
…

ScalaQueryを使用する。

データベーススクリプトによって登録された

Membersテーブルのメンバーに対してクエリを実行してみる。

import play.mvc._
 
import org.scalaquery.session._
import org.scalaquery.session.Database.threadLocalSession
import org.scalaquery.ql.basic.BasicDriver.Implicit._
import org.scalaquery.ql.basic.{BasicTable => Table}
import org.scalaquery.ql.TypeMapper._
import org.scalaquery.ql._
 
package models {
 
    object Members extends Table[(Int, String, Option[String])]("MEMBERS") {
        def id = column[Int]("ID")
        def name = column[String]("NAME")
        def email = column[Option[String]]("EMAIL")
        def * = id ~ name ~ email
        
        def all = (for(m <- Members) yield m.name ~ m.email).list
    }
 
}
 
package controllers {
  
    object Application extends Controller { 
 
        val db = Database.forDataSource(play.db.DB.datasource)
        
        def index = {     
            
            db withSession {
                
                import models._
            
                Template('members -> Members.all)
            
            }
    
        }
 
    }
 
}

playが管理するデータソースとScalaQueryは下記の記述でリンクしている。

val db = Database.forDataSource(play.db.DB.datasource)

おそらく他のScalaのデータアクセスライブラリでも

似たような手順で統合できるだろう。


まとめると、
・JPAは使うな
・あとで解説するAnorm使うといいかも
・ScalaQueryのチュートリアルと似た感じで他のライブラリも使えるよ

次はTesting your application。

テストをお勉強する。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証