<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document PUBLIC
  "-//Apache Software Foundation//DTD XDOC 1.0//EN"
  "http://maven.apache.org/dtd/xdoc_1_0.dtd">

<document>
  <properties>
    <title>データアクセス層 - Data Access Layer</title>
    <author email="kurokkie@users.sourceforge.jp">kurokkie</author>
  </properties>
  <body>
    <section name="データアクセス層">
      <p>
データアクセス層は、ドメインロジックにおけるデータアクセスロジックの API とその実装を提供します。データベースの
読み書きとドメインオブジェクトへのマッピングが主な役割です。データアクセス層はドメイン層の一部であり、ドメイン層
以外のクラスが直接データアクセス層を参照することはありません。データアクセス層では、インターフェースとその実装
を <strong>DAO パターン</strong> によって分離しています。インターフェースは <a href="apidocs/org/unitedfront2/dao/package-summary.html"><code>org.unitedfront2.dao</code></a>
パッケージに、その実装クラスはそれ以下のパッケージに収録されています。現在 United Front 2 で対応してい
るのは <a href="http://www.mysql.com/">MySQL</a> に対する Spring JDBC 実装です。
      </p>
      <div class="info">
        <h5>Note: データアクセス層とドメイン層</h5>
        <p>
ドメイン層とデータアクセス層はインターフェースを通して完全に分離されており、かつパッケージとしても分離しています
が、両者は密接に結びついています。実際のところ、データアクセス層とドメイン層のパッケージは循環依存関係にあり
ます。厳密にはデータアクセス層とドメイン層のクラスは同一パッケージに配置されるべきですが、それではそのパッ
ケージの債務が増えてしまうというデメリットがあるため、ここではディレクトリを分ける程度の意味合いでパッケージを
使っています。本質的には、データアクセス層はドメイン層の一部分と考えてください。
        </p>
      </div>
    </section>
    <section name="データアクセスインターフェース">
      <p>
データアクセスインターフェースは、データへアクセスするために必要となる API を定義しています。基本的に、データ
アクセスインターフェースはデータベーステーブルと１対１に対応しています。データアクセスインターフェースには回復可
能な例外（チェックされる例外）は定義されません。データの整合性違反などを検知した際に発生するのは実行時例外
になります。
      </p>
      <p>
データアクセス API はドメイン層のクラスが持っているようなドメイン（問題対象領域）を意識した高レベル API では
なく、データを読み書きすることに意識を置いた低レベルな API です。SQL のように扱える API が適切です。
登録（ <code>register*</code> ）、取得（ <code>find*</code> ）、更新（ <code>update*</code> ）、
削除（ <code>delete*</code> ）以外のメソッド名は、粒度の点で問題がないか十分検討する必要があります。
オブジェクトのライフサイクルを次に示します。
      </p>
      <div><img src="images/objectLifecycle.png" alt="オブジェクトのライフサイクル"/></div>
      <div class="info">
        <h5>Note: DAO パターンでのインターフェース仕様とテスト</h5>
        <p>
DAO パターンの目的は、ビジネスロジックとデータアクセス実装をインターフェースによって明確に分離することです。こ
れを達成するためには、DAO インターフェースの仕様を正しく記述し、その単体テストを正しく実装する必要があります。
正しい仕様記述と単体テストは、データアクセス実装に関係なく再利用できます。例えば、データアクセス実装がリレー
ショナルデータベースではなくファイルシステムに変更されてもそれらは利用できるはずです。有名なデータアクセステ
ストフレームワークとして <a href="http://www.dbunit.org/">DbUnit</a> が挙げられますが、その名
前が示すとおりデータアクセス実装に依存した単体テストになってしまうため、ここでの採用は適切ではありません。こ
こでいう仕様記述と単体テストはもっと抽象度の高いものである必要があります。United Front 2 における具体
的な仕様記述と単体テスト方式は、<a href="dbc.html">契約による設計</a> の項で述べています。
        </p>
      </div>
      <div class="info">
        <h5>Note: 例外処理</h5>
        <p>
データアクセス層から回復可能な例外処理を排除することで、データアクセス層のコードはかなりシンプルになります。
これは、肥大化しがちなデータアクセス層を薄くするための工夫の一つです。代わりに整合性を確認するための API
を提供することで、ドメイン層にデータの整合性と例外処理の責任を委譲しています。データアクセス層の API は、
データの整合性が違反しないように呼び出されることを前提としています。
        </p>
      </div>
      <subsection name="主要なメソッド">
        <p>
一般的なデータアクセスインターフェースは次のようなメソッドを持ちます。
        </p>
        <div class="smaller">
          <table>
            <tr>
              <th>メソッド名</th>
              <th>説明</th>
            </tr>
            <tr>
              <td><code>register</code></td>
              <td>
ドメインオブジェクトを登録します。ドメインオブジェクトの永続プロパティがデータベースと同期します。主キーなど、データ
ベース側で自動生成される値は、引数のドメインオブジェクトにその値が設定されます。このメソッドを実装するクラスは
インターフェース
<a href="apidocs/org/unitedfront2/dao/Registerable.html"><code>Registerable</code></a>
を実装します。
              </td>
            </tr>
            <tr>
              <td><code>find</code></td>
              <td>
主キーの値を引数として渡し、ドメインオブジェクトを取得します。ドメインオブジェクトの永続プロパティはデータベースと
同期しています。もし対応するドメインオブジェクトが見つからなかった場合、<code>null</code> を返します。この
メソッドを実装するクラスの主キーが一つの整数型である場合、インターフェース
<a href="apidocs/org/unitedfront2/dao/SimpleFindable.html"><code>SimpleFindable</code></a>
を実装します。
              </td>
            </tr>
            <tr>
              <td><code>update</code></td>
              <td>
ドメインオブジェクトを更新します。ドメインオブジェクトの永続プロパティがデータベースと同期します。データベース側で
自動生成される値は、引数のドメインオブジェクトにその値が設定されます。このメソッドを実装するクラスはインター
フェース
<a href="apidocs/org/unitedfront2/dao/Updatable.html"><code>Updatable</code></a>
を実装します。
              </td>
            </tr>
            <tr>
              <td><code>delete</code></td>
              <td>
指定した主キーを持つデータを削除します。削除対象となるドメインオブジェクトのプロパティとなるドメインオブジェクトも
<strong>極力</strong> 削除されます。プロパティとなるドメインオブジェクトが他のドメインオブジェクトからも参
照されている場合などは削除されない可能性があります。このメソッドを実装するクラスの主キーが一つの整数型であ
る場合、インターフェース <a href="apidocs/org/unitedfront2/dao/SimpleDeletable.html"><code>SimpleDeletable</code></a>
を実装します。
              </td>
            </tr>
          </table>
        </div>
        <p>
上記の基本メソッドに加え、次のようなメソッドを持つことがあります。基本的に <i>ColumnName</i> はドメインモ
デルのプロパティに対応します。
        </p>
        <div class="smaller">
          <table>
            <tr>
              <th>メソッド名</th>
              <th>説明</th>
            </tr>
            <tr>
              <td><code>find<i>ColumnName</i></code></td>
              <td>
主キーの値を引数として渡し、ドメインオブジェクトのプロパティ <i>columnName</i> の値を取得します。
              </td>
            </tr>
            <tr>
              <td><code>findBy<i>ColumnName</i></code></td>
              <td>
任意のプロパティ <i>columnName</i> の値を引数として渡し、その値を持った、完全なドメインオブジェクトまたは
そのリストを取得します。もし対応するドメインオブジェクトが見つからなかった場合、<code>null</code> または
空のリストを返します。
              </td>
            </tr>
            <tr>
              <td><code>findBy<i>ColumnName</i>Like</code></td>
              <td>
任意のプロパティ <i>columnName</i> の値の一部を引数として渡し、その値を一部に持った、完全なドメインオ
ブジェクトまたはそのリストを取得します。もし対応するドメインオブジェクトが見つからなかった場合、
<code>null</code> または空のリストをします。
              </td>
            </tr>
            <tr>
              <td><code>find<i>Condition</i></code></td>
              <td>
条件 <i>Condition</i> を完成させるために必要なプロパティの値を引数として渡し、条件に合った完全なドメイ
ンオブジェクトまたはそのリストを取得します。もし対応するドメインオブジェクトが見つからなかった場合、
<code>null</code> または空のリストを返します。
              </td>
            </tr>
            <tr>
              <td><code>count</code></td>
              <td>
永続化されているドメインオブジェクトの総数を返します。
              </td>
            </tr>
            <tr>
              <td><code>update<i>ColumnName</i></code></td>
              <td>
ドメインオブジェクトの一つのプロパティ <i>columnName</i> を更新します。
              </td>
            </tr>
          </table>
        </div>
        <div class="info">
          <h5>Note: 自動生成対象となるデータ</h5>
          <p>
自動生成の対象となるデータは、主キーなど、最小限のものに限定します。日付やコードなどをデータベース側で自動
生成してしまうと、API の仕様が複雑化し、柔軟性が低下します。日付やコードはドメインモデルかテーブルモジュー
ルで設定し、それをデータアクセスオブジェクトへ渡す方式が好ましいでしょう。日付の生成は全てのデータアクセスオブ
ジェクトで利用できますし、日付データ処理専用の <a href="apidocs/org/unitedfront2/dao/DateDao.html"><code>DateDao</code></a>
を使うこともできます。コードの生成は Apache Commons Lang の <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/RandomStringUtils.html"><code>RandomStringUtils</code></a>
を利用できます。コードサンプルとしては、<a href="xref/org/unitedfront2/domain/communication/Mail.html"><code>Mail</code> のソースコード</a>
を参照ください。
          </p>
        </div>
      </subsection>
      <subsection name="静的構造図">
        <p>
全てのデータアクセスインターフェースはインターフェース <a href="apidocs/org/unitedfront2/dao/DateDao.html"><code>Dao</code></a>
を継承しています。インターフェース <code>Dao</code> は日付処理などの、共通的な API を定義しています。
        </p>
        <div><img src="images/dao.png" alt="データアクセスインターフェース"/></div>
      </subsection>
      <subsection name="サンプルコード">
      <p>
サンプルコード <code>SampleDomainDao</code> を示します。完全なコードは
<a href="xref-test/org/unitedfront2/dao/SampleDomainDao.html"><code>SampleDomainDao</code>
のソースコード</a> を参照してください。</p>
<pre name="code" class="java">
public interface SampleDomainDao extends Registerable&lt;SampleDomain&gt;,
    SimpleFindable&lt;SampleDomain&gt;, Updatable&lt;SampleDomain&gt;, SimpleDeletable,
    Dao {

    SampleDomain findByCode(String code);

    int count();
}
</pre>
        <div class="info">
          <h5>Note</h5>
          <p>
<code>Registerable</code> 、<code>Updatable</code> 、
<code>SimpleFindable</code> 、<code>Deletable</code> を実装することは一見冗長な作業のよう
に思えるかもしれません。しかしこれは設計に柔軟性を与えること以上に、仕様の再利用を促進する効果があります。
JavaDoc には、上位のクラスまたはインターフェースからドキュメントを継承する仕組みがあります。仕様に追記事項
があれば、上位のメソッドをオーバーライドし、追記分の仕様のみを記述します。
          </p>
        </div>
      </subsection>
    </section>
    <section name="JDBC 実装">
      <p>
JDBC 実装には Spring の JDBC 抽象フレームワークを利用しています。JDBC 実装はアノテーションベースの
Bean 定義を採用しています。詳細は Spring のドキュメント
<a href="http://static.springframework.org/spring/docs/2.5.x/reference/jdbc.html">Data access using JDBC</a>
を参照してください。
      </p>
      <div class="info">
        <h5>Note: JDBC vs O/R マッピング</h5>
        <p>
JDBC と O/R マッピング製品のどちらを選ぶべきでしょうか？JDBC の利点は、データベースを操作する際に最も効
率的で標準的な SQL を利用できる点です。反面、Java オブジェクトとリレーショナルデータベースの性質の差（イン
ピーダンスミスマッチ）を埋めるためのマッピングロジックを実装する必要があります。O/R マッピング製品の主要な利
点はこのマッピングロジックをフレームワークが担当する点にありますが、SQL で実現できるの全てのケースに対応し
ているわけではなく、場合によっては実装がより複雑になることもあります。United Front 2 はデータ処理が複雑
になると想定されるため、軽量で扱いやすい JDBC 実装を採用しました。単純な SQL の発行とマッピングに対して
は、簡単なフレームワークも用意しています。
        </p>
      </div>
      <subsection name="静的構造図">
        <p>
<a href="apidocs/org/unitedfront2/dao/jdbc/DaoSupport.html"><code>DaoSupport</code></a>
は全ての JDBC 実装を支援する抽象クラスです。<a
href="apidocs/org/unitedfront2/dao/jdbc/SimpleDaoSupport.html"><code>SimpleDaoSupport</code></a>
は <code>register</code> 、<code>find</code> 、<code>update</code> 、
<code>delete</code> などの基本的なメソッドに対するデフォルトの実装を提供します。
        </p>
        <div><img src="images/daoImpl.png" alt="データアクセス実装"/></div>
      </subsection>
      <subsection name="サンプルコード">
        <p>
サンプルコード <code>SampleDomainDaoImpl</code> を示します。完全なコードは <a
href="xref-test/org/unitedfront2/dao/jdbc/SampleDomainDaoImpl.html">SampleDomainDaoImpl
のソースコード</a> を参照してください。
        </p>
<pre name="code" class="java">
// アノテーションベースの Spring Bean 定義。
@Repository(value = "sampleDomainDao")
public class SampleDomainDaoImpl extends SimpleDaoSupport&lt;SampleDomain&gt;
    implements SampleDomainDao {

    // SimpleDaoSupport の抽象メソッドの実装
    @Override
    protected Class&lt;SampleDomain&gt; getDomainClass() {
        return SampleDomain.class;
    }

    // 以下、SampleDomainDao の実装

    @Override
    public SampleDomain findByCode(String code) {
        try {
            return getSimpleJdbcTemplate().queryForObject(
                    "SELECT * FROM SampleDomain WHERE Code = ?",
                    createRowMapper(), code);
        } catch (DataAccessException e) {
            if (logger.isInfoEnabled()) {
                logger.info(e.getMessage());
            }
            return null;
        }
    }

    @Override
    public int count() {
        return getSimpleJdbcTemplate().queryForInt(
                "SELECT COUNT(*) FROM SampleDomain");
    }
}
</pre>
      </subsection>

<script type="text/javascript" src="js/dp.SyntaxHighlighter/Scripts/shCore.js"></script>
<script type="text/javascript" src="js/dp.SyntaxHighlighter/Scripts/shBrushJava.js"></script>
<script type="text/javascript">
dp.SyntaxHighlighter.ClipboardSwf = 'js/dp.SyntaxHighlighter/Scripts/clipboard.swf';
dp.SyntaxHighlighter.HighlightAll('code');
</script>

<script type="text/javascript">
var ID='100354378-dao';
var AD=1;
var FRAME=0;
</script>
<script src="http://j1.ax.xrea.com/l.j?id=100354378" type="text/javascript"></script>
<noscript>
<a href="http://w1.ax.xrea.com/c.f?id=100354378" target="_blank"><img src="http://w1.ax.xrea.com/l.f?id=100354378&amp;url=X" alt="AX" border="0"/></a>
</noscript>

    </section>
  </body>
</document>
