Ruby on Rails
平均的な Ruby on Rails プログラムは SQL コードがあったとしてもその量は極めて限られています。
Ruby on Rails はモデル・ビュー・コントローラー (MVC) パターンをベースにしていることから、大半の Rails アプリケーションは 3 つの構成部分にはっきりと分かれます。
アプリケーションのデータを管理するために必要な振る舞いを受け持つのがモデル(M)です。
一般的に、Ruby on Rails アプリケーションではモデルとデータベース・テーブルの間に 1 対 1 の関係によって実装される傾向にあります。これはデータベースを使う上で重要なポイントです。
この方針は、アプリケーションの構造をシンプルにします。
Ruby on Rails がデフォルトでモデルのデータベース操作に使用するのが、 ActiveRecord というオブジェクト・リレーション・マッピング (ORM) です。
Rails アプリケーション
Ruby on Rails 開発者のスタイルとスタンスは、ActiveRecord が多くの処理を極めて簡単に記述できるため、Rails 開発者は「反 SQL」のスタンスを取りがちです。
このようなスタンスの Rails 開発者は、SQL のほうが理にかなっているとしても、SQL を使いたがりません。
Scala DB アプリケーション
ScalaでDB操作するシステムを開発するとき、
SQL文を意識してプログラムを書くのか、Rails アプリケーションの開発者のように反SQLのスタイルで書くのかは、データベースのスキルに依存します。
ScalaをRuby on Railsのように使いたのであれば、
SQLをこれから覚えるよりは、新しいサービスをとりあえず開発してリリースする方を優先するというスタンスでしょう。
データベースに対するActiveRecordの戦略は、DBのスキーマ情報からモデルクラスを生成することにつきます。
とすれば、Scalaプログラムも同じ生成機能があれば、Ruby on Rails 開発者とのハンディは帳消しできます。
Javaプログラマーは、JavaBeanによってビジネスアプリケーションを書くことに慣れています。
しかし、操作となると DAO (Data Access Object) で相変わらずSQL文と格闘。
ScalaにおいてモデルとなるBeanクラスと、find,create,update,delete操作系関数が生成できれば、いままでこの領域のコードを記述していたよりプログラマーが不要になります。
少人数のプログラマーでより多くの機能をより短時間に生み出すことができると主張するRuby on Rails 開発者と同じです。
結果、ソフトウェア開発費あたりのビジネス価値が増大することに他なりません。
Scalaで使えるBeanクラスは、Seedoフレームワークですでに生成することができるので、操作系のクラスも生成してみよと試みようと次のようなコードを書いてみました。
EMP表を操作するプログラムです。
package ews.servlet.ajax import scala.collection.mutable.{HashMap,LinkedHashMap,HashSet,ArrayBuffer} import seedo._ import seedo.database._ import scott.bean._ /** * The EMP table is operated. */ class User { var key:String = null var column:String = "*" var results:ArrayBuffer[EMP] = null // DELET def remove(userids:Int*) : Int = { var db:Db=null var si = -1 try { db = new Db var sql:DL = db.deleteFrom("emp") if(userids != null) { var str = "" var i = 0 userids.foreach(v =>{ if(i != 0){ str += "," } str += "?" i += 1 }) sql.where("empno in ("+str+")",userids:_*) } si = db.execute.getResultSize db.commit } catch { case e:Exception => { db.rollback println(e.getMessage) throw e } } finally { db.close } si } def remove(userids:List[Int]) : Int = { var db:Db=null var si = -1 try { db = new Db var sql:DL = db.deleteFrom("emp") if(userids != null) { var str = "" var i = 0 userids.foreach(v =>{ if(i != 0){ str += "," } str += "?" i += 1 }) sql.where("empno in ("+str+")",userids:_*) } si = db.execute.getResultSize db.commit } catch { case e:Exception => { db.rollback println(e.getMessage) throw e } } finally { db.close } si } def remove(user:EMP) : Int = { var db:Db=null var si = -1 try { db = new Db db.deleteBean(user) si = db.execute.getResultSize db.commit } catch { case e:Exception => { db.rollback println(e.getMessage) throw e } } finally { db.close } si } // INSERT def create(user:EMP) : Unit = { var db:Db=null try { db = new Db db.insertBean(user) val si = db.execute.getResultSize db.commit } catch { case e:Exception => { db.rollback println(e.getMessage) throw e } } finally { db.close } } // UPDATE def update(user:EMP) : Unit = { var db:Db=null try { db = new Db db.updateBean(user) val si = db.execute.getResultSize db.commit } catch { case e:Exception => { db.rollback println(e.getMessage) throw e } } finally { db.close } } // SELECT def findAll : ArrayBuffer[EMP] = { val db = new Db if(column==null) column = "*" var sql:DL = db.select(column).from("emp") if(key != null) { sql.orderBy(key) } results = db.executeQuery(classOf[EMP]) db.close return results } def find(userids:Int*) : ArrayBuffer[EMP] = { val db = new Db if(column==null) column = "*" var sql:DL = db.select(column).from("emp") if(userids != null) { var str = "" var i = 0 userids.foreach(v =>{ if(i != 0){ str += "," } str += "?" i += 1 }) sql.where("empno in ("+str+")",userids:_*) } if(key != null) { sql.orderBy(key) } results = db.executeQuery(classOf[EMP]) db.close return results } def find(userids:List[Int]) : ArrayBuffer[EMP] = { val db = new Db if(column==null) column = "*" var sql:DL = db.select(column).from("emp") if(userids != null) { var str = "" var i = 0 userids.foreach(v =>{ if(i != 0){ str += "," } str += "?" i += 1 }) sql.where("empno in ("+str+")",userids:_*) } if(key != null) { sql.orderBy(key) } results = db.executeQuery(classOf[EMP]) db.close return results } def getUser(userid:Int) : EMP = { val db = new Db if(column==null) column = "*" var sql:DL = db.select(column).from("emp") sql.where("empno=?",userid) if(key != null) { sql.orderBy(key) } results = db.executeQuery(classOf[EMP]) db.close return results(0) } def setSortkey(key:String) :Unit = { this.key = key } def setColumn(col:String) :Unit = { this.column = col } }
このコードは、モデルとしてBeanと操作関数を別々のクラスとして実装しています。
その理由は、Active RecordsとしてSQLの特徴である集合として複数レコードを扱いたいからです。
しかし、単数としてActiveRecordを扱うのであれば、EMPクラスを継承という形に。
あるいは、ArrayBuffer[EMP]をメンバーにする、いろいろあります。
まだまだ、ActiveRecordのレベルにはありませんが、
Scalaの可変長引数を使ってEMP表のプライマリキーのカラムのEMPNOを引数にして操作します。
EMPNOを要素にしたListを引数にして、可変長引数と同様の操作ができるコードも合わせて書いてみました。
find関数では、データベースをSELECTした結果のレコードデータは、BeanクラスのオブジェクトをArrayBufferに格納して返します。
INSERTするデータもBeanに格納すればいい。
EMPNOによってSELECT、UPDATE、DELETEも問題なし。
問題は、条件指定したSELECT、UPDATE、DELETEする操作です。
リストで条件を記述するようにすればいいと考えているのですが、
実際にScalaでコードを書くプログラマに受け入れられる仕様となるのでしょうか?
コメントを残す
コメントを投稿するにはログインしてください。