LoginSignup
16
14

More than 5 years have passed since last update.

Play Framework でエンティティを使う際の注意点

Posted at

エンハンス

Play Framework でビルドすると、コードのコンパイルの後に、エンティティに対して「エンハンス」という操作が行われます。
EbeanをORマッパーとして使用する場合、

(1)Play Frameworkのエンハンス
(2)Ebeanのエンハンス

という順で行われます。
ここで、上記それぞれのエンハンスで何が行われるかを正しく理解していないとハマることになりますので要注意です。

Play Framework のエンハンス

Play Framework では、ソースコードはプロジェクトホームディレクトリ直下の"app"配下にあることが想定されています。
そこで、"app"配下にあるソースコードを探索して、エンティティに対して、getterとsetterがついていないものはそれをつけるようにします。
その後で、エンティティのフィールド直接アクセスを、getter/setter経由になるように書き換えます。エンティティ内に限らず呼び出し元も書き換えてくれるので便利です。

Ebean の エンハンス

@Entity がついているソースに対して、遅延ローディングや楽観的ロックの制御等の目的で、getterやsetterソースコードが改変されます。
また、Entity 内において、フィールドを直接参照しているコードを、getter/setter経由で呼ぶように改変します。 エンティティ外からのフィールドアクセスについてはsetter/getter経由に呼び直すという書き換えは行いません。

2つのエンハンスを経て何がどうなるか

"app"配下にあるものは何事もなく、フィールド直アクセスであっても遅延ローディングや楽観的ロックの恩恵を受けることができます。
しかし、"app"配下にないコード(別プロジェクトと共通で使うライブラリなど)で、同じ調子でフィールドへの直接アクセスをやっていると、存在するはずのフィールドが存在せず、結果、NullPointerExceptionで落ちたりします
自分は未確認ですが、末尾参考文献によれば、Scalaコードからのアクセスも要注意のようです。
(Play Framework 2 は至る所にScalaコードがあるため、気づかないうちにハマる可能性もあります)

ベストプラクティス

予期せぬ挙動を防ぐために、以下を守った方が安全です。
* フィールドへのアクセスは変数直アクセスではなく、setter/getterを使うようにする。
* そのために、エンティティのsetter/getterは明示的に宣言しておく。(そうしないとコンパイルが通らない)

その他

Play Frameworkのエンハンスでは、関連テーブルのfetchを自動でやってくれるようになります。
なので、エンティティのフィールドにある別のエンティティも、一番上の(外側の)エンティティをfindするだけで、内側のフィールドも値が入っています。Ebeanのエンハンスではそれが行われないため、明示的に内側のフィールドもfetchしておかないと、内側のフィールドはnullになります。
これもハマりポイントです。

参考文献

https://groups.google.com/forum/#!msg/play-framework/XaGlipnEgBc/wPdpB6Hm_4QJ
https://groups.google.com/forum/#!msg/ebean/6sM7_bCZoSc/Rwc354MIPTgJ

16
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
14