SkinnyORMからOracleに接続するために変更した点

SkinnyFrameworkにてScaffoldしたモデルからOracleに接続するために変更したところをメモ。

試した環境としては、

* Windows 8.1
* SkinnyFramework 1.3.4
* Oracle 10g

ですが、他のOS等でも大丈夫だと思います。

# 1. JDBCドライバの依存設定

OracleのJDBCドライバはMavanRepositoryに登録されていないため、以下のいずれかの方法で参照を追加する必要があります。

1. libディレクトリに置く
2. ローカルのMavenリポジトリに発行して利用する

一番手軽なのは方法1で特に説明もいらないと思います。
ただし、方法1の場合だと実行可能JARファイルを出力(`skinny package:standalone`)した際にJDBCドライバが含まれないようですので、ここでは方法2を説明します。

## 1.1. JDBCドライバをローカルのMavenリポジトリに登録する

まずはJDBCドライバを用意して、ローカルのMavenリポジトリに登録します。`mvn`コマンドが必要となりますので、まだの方はここでインストールしましょう。手順は省略します。

JDBCドライバのファイル(ここでは `ojdbc14.jar`)を配置したディレクトリでコマンドプロンプトを開き、以下のコマンドを実行します。

```
rem 以下は1行で入力する
C:\jdbc> mvn install:install-file -Dfile=ojdbc14.jar -DgroupId=com.oracle -DartifactId=ojdbc -Dversion=14 -Dpackaging=jar

rem 改行したい場合は、行の末尾に ^ を付けます
C:\jdbc> mvn install:install-file -Dfile=ojdbc14.jar ^
                                  -DgroupId=com.oracle ^
                                  -DartifactId=ojdbc ^
                                  -Dversion=14 ^
                                  -Dpackaging=jar
```

それぞれのパラメータについてはMavenの説明などを参照してください。ここでは省略します。

# 1.2. JDBCドライバを参照するように ビルドファイル `project/Build.scala` を更新する

上の手順で登録したJDBCドライバを参照するように、ビルドファイルを更新します。

```scala
// project/Build.sbt を一部抜粋
// baseSettings を更新すればいいはず。

lazy val baseSettings = ScalatraPlugin.scalatraWithJRebel ++ herokuSettings ++ Seq(
  // ...

  libraryDependencies ++= Seq(
    // Oracle の JDBC ドライバを追加
    "com.oracle" % "ojdbc" % "14"
  ),
  resolvers ++= Seq(
    // ローカルの Maven リポジトリを追加
    Resolver.mavenLocal
  )

  // ...
)
```

更新後、OracleのJDBCドライバが利用できるようになります。

# 2. Oracleへのコネクション設定

DBへの接続設定は、設定ファイル `src/main/resources/application.conf` へ書きますが、デフォルトのまま利用すると以下のエラーが発生するはずです。

```
2014-11-03 15:24:29.091 ERROR   --- [p1111954787-431] controller.Controllers$search$           : Cannot get a connection, pool error Unable to validate object
java.sql.SQLException: Cannot get a connection, pool error Unable to validate object
```

エラーが発生する理由の一つとして、デフォルトで設定されているコネクション確認用のクエリがOracleに通らないというものがあります。

該当の接続設定の`poolValidationQuery`を、以下のとおりDUAL表を参照するように変更します。

```
(変更前)
poolValidationQuery="select 1 as one"

(変更後)
poolValidationQuery="select 1 as one from dual"
                                    ^^^^^^^^^^
```

# 3. テーブルのカラム名が取得できない?

SkinnyORMからクエリを投げる際に、カラム名をMetaDataから取得しているようですが、自分の環境では取得できなかったため、以下のエラーが発生してました。

```
No column found for persons. If you use NamedDB, you must override connectionPoolName.
```

カラム名が取得できないため、暫定的に手動でカラム名を設定します。
(時間があったら解決方法を探します。)

```scala
// 以下のモデルがあるとして
case class Person(
  id: Long,
  name: String,
  birthDay: DateTime
)

object Person extends ... {

  // columnNames メソッドをオーバーライドして、snake_caseのカラム名を返すようにする。
  override def columnNames = Seq("id", "name", "birth_day")

}
```

# 4. ページネーションが効かない

公式サイトにもありますが、Oracle(とSQLServer)への接続にはページネーションをサポートしていません。

Scaffolding - Skinny Framework
http://skinny-framework.org/documentation/scaffolding.html#skinnyresource's-paginaation-for-oracle,-ms-sqlserver

上記ページに書いてあるとおり、`SkinnyModel#findModels(pageSize: Int, pageNo: Int): List[Model]`をカスタマイズすることでページネーションをすることが可能とあります。
DBにもメモリにもやさしくないですが、件数が少ない場合は全件取得してScalaのメソッドで対応すると楽です。
ちゃんとしたクエリを発行する方法については、調べてから更新しようと思います。

```scala
object Person extends ... {

  // 良くない実装ですが、すごく簡単。
  override def findModels(pageSize: Int, pageNo: Int): List[Person] = {
    val limit = pageSize
    val offset = pageSize * (pageNo - 1)
    findAll().drop(offset).take(limit)
  }

}
```

# まとめ

とりあえず上記の対応をすることで、ScaffoldしたモデルからOracleに接続できるようになります。
それ以外にも必要なところがあれば随時更新していきます。