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は変わらず
※関連コンテンツ