Model(モデル)を使ってデータベースアクセスする[Scala編] (7/7)
作成:2013-02-10 10:25
更新:2013-02-10 10:25
更新:2013-02-10 10:25
■[応用] モデルとフォームのクラスを併用する
ここで作成したMydataクラスでは、name、mail、telといった値が用意されていました。が、改めて作ったテーブルを見てみましょう。この他に「id」という項目もありましたね? プライマリキーであり、自動的に値が割り付けられるように設定した項目です。値は自動設定されますから、フォームで送信することもありませんから不要といえば不要です。
ただし、データの更新や削除などを行おうとすると、処理する対象のレコードはプライマリキー(ここではid)で識別するのが基本となります。そのためにも、idまで項目を含んだモデルにした方がいいでしょう。
ただし! そうすると、今度はFormとモデルで互換性がなくなります。idは自動設定されますから入力フォームを用意するわけにもいきません。idまで用意すると、Formにフォーム情報をバインドしたりすることが難しくなります。
このように、「実際のテーブルと、そのテーブルのデータを扱うためのフォームで項目などが違っている場合」の対処というのはけっこう必要になります。いろいろなやり方があるでしょうが、ここでは「テーブル保管用のモデルクラスと、フォーム保管用のクラスをそれぞれ用意して対処する」ということを行なってみましょう。
下のリスト欄に、モデル(mydata.scala)とコントローラー(Appllication.scala)のソースコードを掲載しておきます。これでIDまで含めてモデルを扱えるようになります。
●モデルでのIDの扱い
モデルクラスであるMydataでは、以下のような項目が引数に追加されるようになりました。
●フォーム用クラス
もう1つ、新たに追加されたのが「MydataForm」というクラスです。これがフォームの値を管理するためのものになります。以下の様なシンプルなcase classです。
Scalaでは、モデルの機能を手作りしていく感覚でコーディングをしていくことになりますが、考えようによっては「モデルといっても入れ物だけ、実際のデータベースアクセス処理はコントローラーにてんこ盛り」といった形骸化されたモデルを作ることはないでしょう。案外、このほうがMVCの分離としては有益なのかも……?
ただし、データの更新や削除などを行おうとすると、処理する対象のレコードはプライマリキー(ここではid)で識別するのが基本となります。そのためにも、idまで項目を含んだモデルにした方がいいでしょう。
ただし! そうすると、今度はFormとモデルで互換性がなくなります。idは自動設定されますから入力フォームを用意するわけにもいきません。idまで用意すると、Formにフォーム情報をバインドしたりすることが難しくなります。
このように、「実際のテーブルと、そのテーブルのデータを扱うためのフォームで項目などが違っている場合」の対処というのはけっこう必要になります。いろいろなやり方があるでしょうが、ここでは「テーブル保管用のモデルクラスと、フォーム保管用のクラスをそれぞれ用意して対処する」ということを行なってみましょう。
下のリスト欄に、モデル(mydata.scala)とコントローラー(Appllication.scala)のソースコードを掲載しておきます。これでIDまで含めてモデルを扱えるようになります。
●モデルでのIDの扱い
モデルクラスであるMydataでは、以下のような項目が引数に追加されるようになりました。
id: Pk[Long] = NotAssignedPkというのはAnormのクラスで、IDを管理するための特別な値として用意されています。Pk[Long]というのは、値がLongのIDということを示します。その後のNotAssignedは、文字通り値が設定されないことを示します。
●フォーム用クラス
もう1つ、新たに追加されたのが「MydataForm」というクラスです。これがフォームの値を管理するためのものになります。以下の様なシンプルなcase classです。
case class MydataForm(name : String,3つの値がそのまま引数にあります。メソッドとしては、MydataFormからMydataを取得する「getMydata」メソッドを用意してあります。これは以下のようなシンプルな処理を行うだけのものです。
mail: String, tel: String)
return Mydata(null, this.name, this.mail, this.tel)Mydataを作成しreturnしています。第1引数(Pk[Long]の値)にはnullを指定してあります。これでMydataFormから、その値を移したMydataが取り出せるようになりました。ではsendformを修正部分を見てみましょう。
var myform = form1.bindFromRequestFormインスタンスをform1に設定している部分では、(MydataForm.apply)(MydataForm.unapply)というようにバインドするクラスをMydataからMydataFormに変更しています。これで、bindFromRequestでFormを取得し、getでMydataFormとして情報が得られるようになります。ここからgetMydataでMydataインスタンスが取り出されます。後は、そのaddDataを呼び出すだけです。
val mydataform: MydataForm = myform.get
val mydata = mydataform.getMydata
val result = mydata.addData
Scalaでは、モデルの機能を手作りしていく感覚でコーディングをしていくことになりますが、考えようによっては「モデルといっても入れ物だけ、実際のデータベースアクセス処理はコントローラーにてんこ盛り」といった形骸化されたモデルを作ることはないでしょう。案外、このほうがMVCの分離としては有益なのかも……?
(by. SYODA-Tuyano.)
※プログラムリストが表示されない場合
AddBlockなどの広告ブロックツールがONになっていると、プログラムリスト等が表示されない場合があります。これらのツールをOFFにしてみてください。
●プログラム・リスト●
※Mydata.scala
package models
import play.api.db._
import anorm._
import play.api.Play.current
import anorm.SqlParser._
case class Mydata(
id: Pk[Long] = NotAssigned,
name: String,
mail: String,
tel: String) {
def addData {
DB.withConnection { implicit c =>
val id: Int = SQL("insert into mydatas (name, mail, tel) values ({name}, {mail}, {tel})").
on('name->this.name, 'mail -> this.mail,
'tel -> this.tel).executeUpdate()
}
}
}
object Mydata {
val data = {
get [anorm.Pk[Long]]("id") ~
get[String]("name") ~
get[String]("mail") ~
get[String]("tel") map {
case id ~ name ~ mail ~ tel =>
Mydata(id, name, mail, tel)
}
}
def getAll: List[Mydata] = {
DB.withConnection { implicit c =>
val datas = SQL("Select * from mydatas").
as(Mydata.data *)
return datas
}
}
}
case class MydataForm(name : String, mail: String,
tel: String) {
def getMydata:Mydata = {
return Mydata(null, this.name, this.mail, this.tel)
}
}
※Application.scala
package controllers
import models._
import play.api._
import play.api.mvc._
import play.api.data._
import play.api.data.Form
import play.api.data.Forms._
object Application extends Controller {
val form1 = Form(
mapping(
"name" -> text,
"mail" -> text,
"tel" -> text
)(MydataForm.apply)(MydataForm.unapply)
)
def index = Action {
val title = "サンプルページ"
val msg = "サンプルのページです。"
val datas = Mydata.getAll
Ok(views.html.index(title, msg, form1, datas))
}
def sendform = Action { implicit request =>
var myform = form1.bindFromRequest
val mydataform: MydataForm = myform.get
val mydata = mydataform.getMydata
val result = mydata.addData
val title = "サンプルページ"
val msg = "名前:" + mydata.name + ", メール:" + mydata.mail
Ok(views.html.index(title, msg, myform, null))
}
}
※index.scala.htmlは変わらず
※関連コンテンツ