技術解説

PetShopで学ぶデータベース・アクセスの実装パターン

デジタルアドバンテージ
2004/03/27

Page1 Page2 Page3 Page4

データベースからUIまでのデータの流れ

 以上のような構造を踏まえた上で、ここからは実際のコードについて見ていく。これにより、コンポーネント間のインターフェイスの実装パターンがより具体的に理解できるはずだ。

 ここでは商品(Product)データに着目して、データの流れをプレゼンテーション層から追っていくことにする。どのデータ(ビジネス・エンティティ)でも、コンポーネント間のインターフェイスという点に関しては、それほど大差ない。

プレゼンテーション層における実装

 さて、商品データが使用される1つの場面は、「PetShopアプリケーションの概要」の項で示した、カテゴリ選択後の商品一覧画面である。この画面は「Web」という名前のディレクトリにあるファイル「Category.aspx」で記述されている。

 このファイルで商品一覧を表示するのは、以下に示した「SimplePager」コントロール(<controls:SimplePager>要素)の記述部分である。SimplePagerコントロールは、標準のRepeaterコントロールを継承して独自のページング機能を追加した、PetShop独自の「Webカスタム・コントロール」である(これはWeb / Controls / SimplePager.csで実装されている。詳細についてはここでは割愛)。

……
<controls:SimplePager id="products" runat="server" ……>
  <HEADERTEMPLATE>
    <TABLE cellSpacing="0" cellPadding="0">
    <TBODY>
    <TR class="gridHead">
      <TD>Product ID</TD>
      <TD>Name</TD>
    </TR>
  </HEADERTEMPLATE>
  <ITEMTEMPLATE>
    <TR class="gridItem">
      <TD>
        <%# DataBinder.Eval(Container.DataItem, "Id") %>
      </TD>
      <TD>
        <A href='Items.aspx?productId=<%# DataBinder.Eval(Container.DataItem, "Id") %>'>
          <%# DataBinder.Eval(Container.DataItem, "Name") %>
        </A>
      </TD>
    </TR>
  </ITEMTEMPLATE>
  <FOOTERTEMPLATE>
    </TBODY>
    </TABLE>
  </FOOTERTEMPLATE>
</controls:SimplePager>
……
Web / Category.aspxの商品一覧表示部分
独自のページング機能を追加した「SimplePager」カスタム・コントロールにより、データソース要素のIdプロパティとNameプロパティを表示する。

 この一覧表示のためのコントロールでは、データソースにあるIdプロパティと、Nameプロパティをデータ連結により表示している(太字部分)。

 データソースの設定は、コードビハインド・ファイルである同ディレクトリにあるファイル「Category.aspx.cs」で行われている。この部分を抜き出したのが次のコードである(なお、以降のコードでは、ファイルで参照している名前空間を指定するusing文と、定義するクラスの名前空間を指定するnamespace文も含めて掲載している。これによりクラス間(コンポーネント間)の依存関係にも着目していただきたい)。

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections;
using System.Data;
using System.Web.Caching;

using PetShop.BLL;
using PetShop.Web.Controls;

namespace PetShop.Web {

  public class Category : Page {
    ……
    Product product = new Product();
    IList productsByCategory = product.GetProductsByCategory(categoryKey);
    ……
    products.DataSource = productsByCategory;
    ……
  }
  ……
Web / Category.aspx.csのデータ連結部分
変数categoryKeyには、選択されたカテゴリ名が文字列で入っている。また、変数productsはSimplePagerカスタム・コントロールを参照している。なお実際のコードでは、カテゴリごとの商品一覧をキャッシュに格納して、通常はそちらを返すようになっている。

 このコードでは、ビジネス・ロジック・コンポーネントのProductクラス(PetShop.BLL名前空間)をインスタンス化し、そのGetProductsByCategoryメソッドにより、カテゴリ名から商品一覧を得ている。このGetProductsByCategoryメソッドはビジネス・ロジックの具体的な実装の1つである。

 GetProductsByCategoryメソッドの戻り値は、実際にはArrayListクラスのオブジェクトである。そして、そのArrayListオブジェクトには、商品情報であるProductInfoクラスのオブジェクトがリストとして格納されている。しかし、これを具体的な配列やオブジェクトでなく、IListインターフェイスの参照として受け取っている点はポイントの1つである。データ連結を行うコントロールでは、この参照と、それにより参照される各要素の表示すべきプロパティ名さえ分かっていれば一覧表示が可能である。

ビジネス層における実装

 ビジネス・ロジックを記述しているGetProductsByCategoryメソッドですべきことは、指定されたカテゴリの商品一覧をデータ層から取得することである。簡単な処理なので、ビジネス・ロジックというほどのものは記述されていないが、このメソッドを持つProductクラスの定義は次のようになっている。

using System.Collections;
using PetShop.Model;
using PetShop.IDAL;

namespace PetShop.BLL {

  public class Product {

    public IList GetProductsByCategory(string category) {
      IProduct dal = PetShop.DALFactory.Product.Create();
      return dal.GetProductsByCategory(category);
    }

    public IList GetProductsBySearch(string text) {
      ……
    }
  }
}
BLL / Products.csのGetProductsByCategoryメソッド
このProductクラスでは、商品検索のためのGetProductsBySearchメソッドも実装されている。これらのメソッドは、商品に関するビジネス・ロジックの実装である。

 ここではまず、データ・アクセス・コンポーネント内の商品情報を扱うクラスのインスタンスを、ファクトリ・クラス(ここではPetShop.DALFactory名前空間のProductクラス)の唯一の静的メソッドであるCreateメソッドにより作成する(太字部分)。

 DBMSとしてSQL Serverを使用するという設定にしている場合には、このメソッドの戻り値はSQL ServerのProductテーブルにアクセスするクラスのオブジェクトとなるが、そのクラスのメソッドへのアクセスはインターフェイス(この場合ではIProduct)経由で行われるため、データベースがOracleであっても、ここでのコードに変化はない。

 ビジネス・ロジック・コンポーネントのすべてクラスは、このようにまずPetShop.DALFactory名前空間の各クラスのCreateメソッドによりデータ・アクセス・コンポーネントのインスタンスを取得し、それによってデータベースからデータを得る形になっている。

 商品情報を表すビジネス・エンティティであるProductInfoクラスについてもここで見ておこう。すでに述べたように、このクラスのインスタンスによってコンポーネント間でのデータの受け渡しが行われる。

using System;

namespace PetShop.Model {

  [Serializable]
  public class ProductInfo {

    // Internal member variables
    private string _id;
    private string _name;
    private string _description;

    public ProductInfo() {}

    public ProductInfo(string id, string name, string description) {
      this._id = id;
      this._name = name;
      this._description = description;
    }

    public string Id {
      get { return _id; }
    }

    public string Name {
      get { return _name; }
    }

    public string Description {
      get { return _description; }
    }
  }
}
Model / ProductInfo.csで定義された商品情報を表すモデル
実データの格納をコンストラクタで行い、そのデータをプロパティ経由で外部に公開する。

 このクラスでは実データの格納をコンストラクタでのみ行い、そのデータは読み出し専用プロパティとして外部に公開するようになっている。ロジックを記述したメソッドは持っていない。

 そしてクラスにはSerializable属性が付けられており、データをシリアル化(シリアライズ)して、XMLデータとしてほかのプロセス/システムとのデータ転送も可能な設計となっている。オブジェクトのシリアライズに関しては「連載:.NETで簡単XML」の後半で詳しく解説されている。

 ほかのコンポーネントのクラスをまったく利用していない点がこのクラスのポイントである。つまり、完全に抽象的なデータの構造を持っているということだ。

 以上の特徴はビジネス・エンティティ・コンポーネントのすべてクラスに共通している。


 INDEX
  [技術解説] PetShopで学ぶデータベース・アクセスの実装パターン
    1.PetShopアプリケーションの概要
    2.PetShopの論理アーキテクチャとファイル構造
  3.データベースからUIまでのデータの流れ(1)
    4.データベースからUIまでのデータの流れ(2)
 


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間