Query Object
An object that represents a database query.
-
SQLを直接使うと生じる問題:
- アプリケーション開発者がSQLに不慣れ
- アプリケーションコードとSQLとの密結合
- 用途特化のfinderメソッドでカプセル化することで回避できる
-
新たな問題
- ad hocなクエリの構築が困難
- SQLコードの重複
-
GoFのInterpreterパターン
- SQLを構築するInterpreter
How It Works
- InterpreterパターンのSQL向け応用
-
Query Objectは最初から作り込まずスモールスタートにせよ
- 任意のSQL文を表現するには、柔軟に作り込む必要がある
- が、アプリケーションで必要なSQLの機能は限られている
-
Query Objectの役割
- オブジェクト構造で問い合わせを表現・SQLに変換
- クライアントコードはQuery Objectを利用して様々な問い合わせができる
-
DBのテーブル名やカラム名ではなく、Domain Modelのクラス名やフィールド名でクエリできるようにする
- 両者が異なる場合、非常に有用
-
Metadata Mappingも参照のこと
- マッピングを手書きせずに済む
- RDBMS方言も吸収できる
-
高度な利用法: 冗長なDB問い合わせの省略
- 取得済みの集合をさらにAND条件で絞り込むようなケース
- DBに問い合わせる代わりにIdentity Mapからフェッチして返す
-
バリエーション: ドメインオブジェクトを例示して問い合わせる
- 名前が
Fowler
、他のフィールドがnullのオブジェクトを渡す - 名前が
Fowler
な全オブジェクトが返ってくる - 限界: 複雑な問い合わせはできない
- 名前が
When to Use It
- たいへん複雑で高度なパターンなので、使われないケース多し
-
Domain ModelとData Mapper利用時に使う
- 【補】Data Mapperに特定用途のfinderメソッドが乱立するのを防ぐ
-
Metadata Mappingも一緒に使う
-
Query Objectの中でDBスキーマとDomain Modelのフィールドマッピング多数
- いちいち手書きしたくない
-
-
Query Objectパターンのアドバンテージ
- DBスキーマの知識の隠蔽
-
複数のスキーマへの対応
- 【補】1つのDomain Modelが複数テーブルからなるケースのことを言っている?
-
クエリ複数発行の回避
- 【補】LaravelのEloquent/BuilderのEager Loadがこれに近い気持ちか
- 作らずに買うという選択肢
Further Reading
- Query Object [Alpert et al.]
- Specification pattern [Evans and Fowler], [Evans]
コード例
- 略
-
コード例を一部改変して起こしたクラス図
-
【補】流れ
- ドメインオブジェクトのクラス名を渡してQueryObject構築
- QueryObjectにCriteriaを追加してクエリを構築していく
-
QueryObjectのexecuteメソッドにUnitOfWorkを渡して実行
-
引数のUnitOfWorkにドメインオブジェクトのクラス名を渡して、対応するDataMapperを取得
-
【所感】UnitOfWork不使用時はRegistryに問い合わせるのかな
- 参照しかしない場合とか
-
-
メンバのCriteriaのコレクションをSQL文のwhere句に変換
- Interpreterパターン
-
【所感】複雑なSQL文に対応する場合はCompositeパターンも必要だと思う
- CompositeCriteriaがCriteriaを集約する木構造
- DataMapperのfindWhereにwhere句を渡してドメインオブジェクトのコレクションを取得
-
-
【所感】LaravelのDBやEloquentのBuilderは近くて遠い感じ
-
似ているところ
- メソッドチェーンでクエリを構築していく
- get()メソッドでDBに問い合わせ、結果のコレクションを得る
-
異なるところ
-
テーブルのカラム名で問い合わせる
-
Eloquentをドメインオブジェクトと見なすなら、モデルのフィールド名と一致する
- Active Recordなので
- scope機能を使えばドメインの言葉で問い合わせできる
-
- 検索条件を「CriteriaのComposite」という形では抽象化していない
-
Data Mapper不在
- DB: Record Setをそのまま返す
- Eloquent: Active Recordなので
-
-
英語
-
be geared to
- 〜向けに作られている