( ꒪⌓꒪) ゆるよろ日記

( ゚∀゚)o彡°オパーイ!オパーイ! ( ;゚皿゚)ノシΣ フィンギィィーーッ!!!

scalaのWebフレームワーク liftで遊ぶ(8) - いよいよModelでCRUDするぜ?

目次はこちら。
scalaのWebフレームワーク liftで遊ぶ 目次 - ゆろよろ日記


こんばんは、土井善晴です。
今日はね。Modelをやりますよー。
最近のフレームワークとおんなじでね、Liftでも簡単にCRUDが作れるんですよー。


ではやってみましょうかね。

を参考にやりますよー。

LiftでのORM

LiftでのORMの特徴はこんな感じ。

  1. テーブル操作を行うMetaMapperとモデルクラスを定義するKeyedMapperを作成すれば利用可能。
  2. 定義とMigrationが一元化されている。モデルクラスを定義すると、アプリケーション起動時に自動的にテーブルが作成・更新される。
  3. CRUD操作メソッドやfinderメソッドは自動的に追加される。RailsのAR的なアプローチ
  4. モデルクラスに、formタグやtableタグなどのHTMLを出力するメソッドがある。

じゃじゃじゃじゃじゃじゃじゃあじゃあじゃあ、動かしてみますよ。

モデル作り

mavenでプロジェクトを作成する。


CRUDの動作確認用のプロジェクトを作りますよ。

mvn archetype:create -U  -DarchetypeGroupId=net.liftweb  -DarchetypeArtifactId=lift-archetype-basic -DarchetypeVersion=0.9  -DremoteRepositories=http://scala-tools.org/repo-releases  -DgroupId=com.yuroyoro -DartifactId=lift-model

基本的なDBへのマッピング

net.liftweb.mapperパッケージはDBへのマッピングを提供する。

liftでモデルを作るには、こんな感じになる。

package com.yuroyoro.model

import net.liftweb.mapper._

object Entry extends Entry with KeyedMetaMapper[Long,Entry]{
  override def dbTableName = "entries"
  override def fieldOrder = id :: title :: entry :: Nil
}

class Entry extends KeyedMapper[Long,Entry]{
  def getSingleton = Entry // Metaオブジェクト
  def primaryKeyField = id // 主キーの設定
  
  object id extends MappedLongIndex(this)
  object title extends MappedString(this,300)
  object entry extends MappedString(this,8192)
}

ソースの説明。

  1. net.liftweb.mapper.KeydMapperを継承したclassを定義する。
    1. モデルオブジェクト
    2. KeyedMappaerには、主キーの型と自信のクラスを型パラメータとして与える
    3. getSingletonで、2のMetadataオブジェクトを取得できるようにする
    4. primaryKeyFieldに主キーとなるフィールドを設定する
    5. フィールドを定義する。(object id extends MappedLongIndex(this))
  2. 1を継承して、net.liftweb.mapper.KeyedMetaMapperというtraitをwithで実装したObjectを用意する。
    1. KeyedMetaMapper : データベース操作(Create,Finderなど)が定義されているtrait。
    2. マッピングするテーブル名を定義する。(override def dbTableName = "entries" )
      1. MappedField:フィールドの属性をあらわすクラス。
      2. MappdedString,MappedLongなど各種の型に対応したクラスがある。
    3. フィールドの並び順をListで定義する。(override def fieldOrder = id :: entry :: Nil )


このようにすると、基本的なCRUD操作のメソッドが利用できる。(表の中のAはModelの型。)

create: A Modelオブジェクトを生成する。
find(by: QueryParam[A]*): Can[A] 1レコードを対象としたfinderメソッド。引数にQueryParamを渡すことで検索条件を指定できる。
findAll: List[A] 全件検索用のfinderメソッド。
findAll(by: QueryParam[A]*): List[A] 検索条件を指定したfinderメソッド。条件にあったレコードをすべてListで返す。
save(toSave: A): Boolean 引数のModelオブジェクトの状態をDBに保存する。成功したかがBooleanで返される。


検索条件を指定するQueryParamクラスは、以下のようなcaseクラスを継承している。

Cmp[O 比較を行う条件。フィールド、比較のオペレータ(OprEnum.Eqlなど),比較対象の値,他のフィールドの順で指定する。Cmp(title,OprEnum.Eq,"ほげほげ",Empty)など
OrderBy[O Order Byを指定する。
ByList[O INを指定する。フィールド名と、値のListを渡す。実際のSQLはORで連結。
BySql[O SQLを直接指定する。queryには、PreparedStatementのようにプレースホルダを含むことができ、paramsにパラメータを設定できる。
MaxRows[O 取得件数を指定する。
StartAt[O 検索対象のレコードから開始位置を指定する。


1から10件目のレコードを取得するには、こんな感じにすればよい。

 Entry.findAll(StartAt(0), MaxRows(10))


Cmpクラスを利用して検索条件を指定しても良いが、以下のObjectでもっと簡単に条件を指定できる。

By 指定したフィールド名で、一致する値のレコードを検索する。By(title,"hogehoge")だとtitle='hogehoge'となる。
NotBy 指定したフィールド名で、一致しない値のレコードを検索する。NotBy(title,"hogehoge")だとtitle<>'hogehoge'となる。
ByRef 指定したフィールド名で、もう一方のフィールド名と一致する値のレコードを検索する。ByRef(title,id)だとtitle=idとなる。
NotByRef 指定したフィールド名で、もう一方のフィールド名と一致しない値のレコードを検索する。NotByRef(title,id)だとtitle<>idとなる。
By_> 指定したフィールド名で、引数の値より大きい値を持つレコードを検索する。比較する値には、他のフィールド名も指定できる。By_>(id,5)だとid>5となる。
By_< 指定したフィールド名で、引数の値より小さい値を持つレコードを検索する。比較する値には、他のフィールド名も指定できる。By_<(id,5)だとid < 5となる。
NullRef 指定したフィールド名がNULLであるレコードを検索する。NullRef( title )だと title IS NULL となる。
NotNullRef 指定したフィールド名がNULLではないレコードを検索する。NotNullRef( title )だと title IS NOT NULL となる。


今回はモデルクラスのメソッドをまとめてみた。

次回は、実際にモデルを利用して検索/新規作成/更新/削除を行う画面を作成しますよ。