読者です 読者をやめる 読者になる 読者になる

ReladomoというORMを触ってみた

Reladomoゴールドマン・サックスが公開しているJava向けORMです。

https://github.com/goldmansachs/reladomo-kataチュートリアルが公開されていたので触ってみました。

ちなみにReladomoもReladomo-KataもApache License 2.0です。

Chaining

JavaのORMにも色々種類があると思いますが、Reladomoの特徴的な機能としてChainingが挙げられます。

Chainingという単語自体には色々意味があるようですが、Reladomoが持つChainingは監査のためにオブジェクトに対する変更履歴を全て保存し後から履歴を追跡出来るようにするための機能です。

監査用履歴は基本的には通常のアプリケーションから利用されることはあまりありませんが、履歴の保存や定期的な参照が必要になるようなユースケースは多数存在します。(たぶん) こういった履歴管理はエンティティの変更ごとに追加等が必要になるので結構な労力が必要になりますが、 Reladomoを使うとその辺の履歴管理をよしなにやってくれるので他のORMを使うより効率的に開発ができるということのようです。

肝心の履歴をどうやって保持するかですが、基本的にはデータの有効期限を繋いでいくモデリングになっているようです。 具体的には以下のようにIN_Z・OUT_Zというカラムでデータが有効になった日時とデータが更新されて無効になった日時を保存します。

item id name IN_Z OUT_Z
1 foo 2004-04-01T10:00Z 2004-04-01T12:00Z
1 bar 2004-04-01T12:00Z

このようなItemテーブルがあるとき、Reladomoに itemId == 1 のitemを問い合わせると自動的にOUT_Zを指定したクエリを生成して問い合わせてくれます。

SELECT * FROM ITEM
WHERE item_id = 1 AND OUT_Z = '9999-12-01 23:59:00.000'

ちなみにIN_Z, OUT_Zというカラム名9999-12-01... (infinity)などはオプションで指定可能です。

もちろんitemId = 1 のアイテムに関する変更履歴やある時点での情報を取得することも可能です。 データ更新時は履歴のことは考えずにデータをORM経由で更新すればOKです。

またデータの削除の代わりにOUT_Zに入っているinfinityを具体的な時刻に更新することでデータを無効にするterminate操作が可能です。

BiTemporal Modeling

履歴管理にはさらにBiTemporal Modelingというモデリング手法があります。

ざっくりいうとアプリケーションレベルの有効・無効時刻(BussinessDate)とトランザクションが起きた時刻レベルでの有効・無効時刻(ProcessingDate)を組み合わせる方式になっています。 この方式で時刻を管理すると、8/1にあるべきだった更新の反映が8/4日になってしまったので今までの履歴を全部調節する必要があるが、その際にどういう変更があったかも追跡できるようにしておきたいといった要望に答えることができます。

BiTemporal Modelingについては別途まとめたので詳しくはそちらも御覧ください。

二種類の時刻を使った詳細な履歴管理を行いたい場合、自分で色々書いているとどうしても複雑になりミスも考えられるのでORMである程度吸収されるというのはかなり魅力的に感じました。

メモ

以下は触ってみた感想メモです。

オブジェクト定義

  • objectの定義はxmlで書くらしい。最初はうおー現代ーと思ったけどIntelliJXMLサポートが賢いので意外と悪くなかった。IntelliJnoNamespaceSchemaLocation を見て適切に補完を出してくれるらしい。
    • schemaにはnullableとかmaxlengthやらindexやらを書く必要があるのでとにかく補完が効くのが重要で、それが達成されているのでjsonyamlかみたいなのはそこまで重要じゃないかなと思った。
    • そしてスキーマファイルにはちゃんと属性の意味がコメントで書いてあった・・!コードジャンプで行ける・・!
  • とはいえプログラミング言語で書きたい気持ちがあったりなかったり。

コード生成

  • コード生成はチュートリアルにある構成ならmvn compileですぐ出来る。
  • srcとgenerated_src以下にコードが生成される。srcの方は一回だけ生成して自分でいじる用途(ほぼ空のクラスが出来るだけ)。generated_srcの方はコード生成っぽいコードが出来る。
  • ついでにgenerated_resourceの方にddlも書き出してくれる。

コード

  • selectした結果がPersonListみたいな型になって、これScalaから使いにくいのではと思ったけどListのサブクラスになっているらしく、やりたければすぐasScalaできそうだった。(まだしてない)

この後、使い方について書こうかなと思ったんですがtutorialの例みるだけでいい感じになれそうだったので省略。