Upload page content

You can upload content for the page named below. If you change the page name, you can also upload content for another page. If the page name is empty, we derive the page name from the file name.

File to load page content from
Page name
Comment

Locked History Actions

Circumflex_ORM

Circumflex ORM

参考

※ひどいことに、mavenリポジトリにあるもの(2011/10時点)は、おそらくScala2.8用。2.9で動作させるとNoSuchMethodException等が発生するので注意。

評価

良い点

  • タイプセーフに(中途半端ではあるが)こだわっている。普通ならどうやってもなりようがないSQLをかなりタイプセーフなものに仕立て上げている。正解かどうかはおいておいても、この点は他のORMと一線を画している。
  • コード量が非常に小さく、とりまわしが楽。
  • 様々なRDBの方言に対応可能なようだ、コードを書けば。

悪い点

  • circumflexというウェブフレームワークを前提としており、「一つのデータベース」しか扱うことができない(この点はPlay Frameworkのanormとも全く同じ)。複数のデータベースを切り替えたり、同時に使用したりすることは不可能。つまり、そこから切り離して「一般的なORM」として使うのはそのままではできず、改造が必要になる。なぜなら、ウェブフレームワークの起動時に与えられたデータベース接続定義をあらゆるところから「静的に」参照しているから。

とにかく動かしてみる

Circumflex ORMはCircumflexというウェブフレームワークの一部だが、ここでは単体で使用する。 DBはH2を用いた。

テーブルの定義とデータベース生成

Country, Cityはサンプルそのまま

import ru.circumflex._
import ru.circumflex.orm._
import ru.circumflex.core._

class Country extends Record[String, Country] {
  val code = "code".VARCHAR(2).NOT_NULL.DEFAULT("'ch'")
  val name = "name".TEXT.NOT_NULL

  def cities = inverseMany(City.country)
  def relation = Country
  def PRIMARY_KEY = code
}

object Country extends Country with Table[String, Country]

class City extends Record[Long, City] with SequenceGenerator[Long, City] {
  val id = "id".BIGINT.NOT_NULL.AUTO_INCREMENT
  val name = "name".TEXT
  val country = "country_code".TEXT.NOT_NULL
          .REFERENCES(Country)
          .ON_DELETE(CASCADE)
          .ON_UPDATE(CASCADE)

  def relation = City
  def PRIMARY_KEY = id
}

object City extends City with Table[Long, City]

object Creation {

  def main(args: Array[String]) {
    
    val cx = Circumflex
    cx("orm.connection.driver") = "org.h2.Driver"
    cx("orm.connection.url") = "jdbc:h2:sample"
    cx("orm.connection.username") = "sa"
    cx("orm.connection.password") = ""
    
    val unit = new DDLUnit(Country, City)
    unit.CREATE()
  }
}

どんなDDLが生成されているのか?

  println(Country.sqlCreate)
  println(City.sqlCreate)

レコードの挿入

      val country = new Country
      country.code := "jp"
      country.name := "japan"
      try {
        country.INSERT_!()
        COMMIT()
      } catch {
        case e:Exception => { e.printStackTrace(); }
      }

バグ

git上では修正されているが、バイナリリリースはされていない(2011/10/24)

dialect.scalaの207行目付近

  def columnDefinition[R <: Record[_, R]](field: Field[_, R]): String = {
    var result = field.name + " " + field.sqlType
    if (field.notNull_?) result += " NOT NULL"
    if (field.unique_?) result += " UNIQUE" // <-- これが抜けてる
    result += defaultExpression(field)
    return result
  }

ドキュメント翻訳

- 本家ドキュメント翻訳