PoEAA ch13 Query Object

PoEAA勉強メモ

出典: 


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]

コード例

  • コード例を一部改変して起こしたクラス図

    • クラス図
  • 【補】流れ

    1. ドメインオブジェクトのクラス名を渡してQueryObject構築
    2. QueryObjectにCriteriaを追加してクエリを構築していく
    3. QueryObjectのexecuteメソッドにUnitOfWorkを渡して実行

      1. 引数のUnitOfWorkにドメインオブジェクトのクラス名を渡して、対応するDataMapperを取得

        • 【所感】UnitOfWork不使用時はRegistryに問い合わせるのかな

          • 参照しかしない場合とか
      2. メンバのCriteriaのコレクションをSQL文のwhere句に変換

        • Interpreterパターン
        • 【所感】複雑なSQL文に対応する場合はCompositeパターンも必要だと思う

          • CompositeCriteriaがCriteriaを集約する木構造
      3. 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

    • 〜向けに作られている