技術解説

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

デジタルアドバンテージ
2004/03/27
Page1 Page2 Page3 Page4

データ層における実装

 残るはデータ・アクセス・コンポーネントのみである。まず、先ほどビジネス・ロジックの実装時に使用されていたCreateメソッドを含むファクトリ・クラスの実装は次のようになっている。

using System;
using System.Reflection;
using System.Configuration;
using System.Security.Policy;

namespace PetShop.DALFactory {

  public class Product {

    public static PetShop.IDAL.IProduct Create() {
      string path = ConfigurationSettings.AppSettings["WebDAL"];
      string className = path + ".Product";

      return (PetShop.IDAL.IProduct)Assembly.Load(path).CreateInstance(className);
    }
  }
}
DALFactory / Products.csのCreateメソッド
このクラスで定義されているメソッドは、このCreateメソッドだけである。このメソッドは、Web.Configファイルの設定に従って、実際にデータベースにアクセスするクラスのインスタンスを返す。

 ここで、「WebDAL」というキーワードに対する値は、Web.Configファイルで次のように記述されている(DBMSとしてSQL Serverを利用する場合)。

<add key="WebDAL" value="PetShop.SQLServerDAL" />
Web / Web.Configで記述されている使用DBMSの設定

 「PetShop.SQLServerDAL」というのは、後に示すSQLServerディレクトリにあるProducts.csファイルで定義されているProductクラスが含まれるアセンブリの名前である。

 Createメソッドのコードでは、まずそのアセンブリをAssembly.Loadメソッドによりロードし、さらにPetShop.SQLServerDAL.ProductクラスのインスタンスをCreateInstanceメソッドにより作成する。この手順は、クラス名から動的にそのクラスのインスタンスを生成する標準的な方法である。

 このような実装になっているため、SQL Serverの代わりにOracleを利用する場合には、Web.ConfigファイルでWebDALに対する値を「PetShop.OracleDAL」に書き換えるだけでよい(もちろんOracle用のアセンブリが準備されていなければならない)。

 続いてCreateメソッドの戻り値の型になっているIProductインターフェイスの定義を示す。

using System;
using System.Collections;

namespace PetShop.IDAL{

  public interface IProduct{

    IList GetProductsByCategory(string category);
    IList GetProductsBySearch(string[] keywords);
  }
}
IDAL / IProduct.csで定義されているインターフェイス

 このファイルだけでは少々分かりにくいので、オーダー情報のテーブルにアクセスするクラス用のインターフェイスも示しておこう。

using System;
using PetShop.Model;

namespace PetShop.IDAL{

  public interface IOrder {

    int Insert(OrderInfo order);
    OrderInfo GetOrder(int orderId);
  }
}
IDAL / IOrder.csで定義されているインターフェイス

 実際にデータベースにアクセスする各DBMS用のクラスのセットは、これらのインターフェイスで宣言されているメソッドさえ定義しておけば、プラグインのように差し替えて使えるというわけである。

 上記のIProductインターフェイスを実装したSQL Server用の商品情報取得クラスであるProductクラスは次のようになっている。ここでは、詳細については触れないが、PetShopではすべて「接続型」のデータベース・アクセスで記述されている(データセットは一切使われていない)。.NETにおけるデータベース・アクセスの詳細は「連載:ADO.NET基礎講座」で解説されている。なお、PetShop 3.0ではストアド・プロシージャも一切使用されていない(「Middleware Benchmark」の目的では、ストアド・プロシージャを使ってはいけないらしい)。

using System;
using System.Collections;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using PetShop.Model;
using PetShop.IDAL;

namespace PetShop.SQLServerDAL {

  public class Product : IProduct {

    private const string SQL_SELECT_PRODUCTS_BY_CATEGORY = "SELECT ProductId, Name FROM Product WHERE Category = @Category";
    private const string PARM_CATEGORY = "@Category";

    public IList GetProductsByCategory(string category) {

      IList productsByCategory = new ArrayList();

      SqlParameter parm = new SqlParameter(PARM_CATEGORY, SqlDbType.Char, 10);
      parm.Value = category;

      using (SqlDataReader rdr = SQLHelper.ExecuteReader(SQLHelper.CONN_STRING_NON_DTC, CommandType.Text, SQL_SELECT_PRODUCTS_BY_CATEGORY, parm)) {
        while (rdr.Read()){
          ProductInfo product = new ProductInfo(rdr.GetString(0), rdr.GetString(1), null);
          productsByCategory.Add(product);
        }
      }

      return productsByCategory;
    }

    public IList GetProductsBySearch(string[] keywords) {
      ……
    }
  }
}
SQLServer / Products.csのGetProductsByCategoryメソッド
このメソッドでは、SQL Serverにselect文を発行して、レコードを読み込み、ProductInfoオブジェクトのリストとしてビジネス層に返す。

 このGetProductsByCategoryメソッドでは、SqlDataReaderクラスで読み取ったレコードをProductInfoオブジェクトに詰め替え、それをArrayListオブジェクトに格納して返しているのが分かる。

 データベースに対して実際にSQL文を実行するメソッドは、SQLHelperクラスの静的メソッドにまとめられている。このクラスは、実は「Data Access Application Block for .NET」としてMSDNで公開されているSQLHelper.csの一部を切り出して流用したものだ。

 Data Access Application Block for .NETのSQLHelper.csは、ADO.NETを利用してSQL Serverを扱うプログラミングを行う際にいつも記述しなくてはならないような一連のコードをユーティリティ・クラス(ヘルパー・クラス)としてまとめたものである。

 上記のGetProductsByCategoryメソッドで使用されているSQLHelper.ExecuteReaderメソッドのコードも次に示しておく。

using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Collections;
using PetShop.Utility;

namespace PetShop.SQLServerDAL {

  public abstract class SQLHelper {

    public static readonly string CONN_STRING_NON_DTC = ConnectionInfo.DecryptDBConnectionString(ConfigurationSettings.AppSettings["SQLConnString1"]);
    public static readonly string CONN_STRING_DTC_INV = ……
    public static readonly string CONN_STRING_DTC_ORDERS = ……

    public static int ExecuteNonQuery(……) { …… }

    public static SqlDataReader ExecuteReader(string connString, CommandType cmdType, string cmdText, params SqlParameter[] cmdParms) {

      SqlCommand cmd = new SqlCommand();
      SqlConnection conn = new SqlConnection(connString);

      try {
        PrepareCommand(cmd, conn, null, cmdType, cmdText, cmdParms);
        SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
        cmd.Parameters.Clear();
        return rdr;
      } catch {
        conn.Close();
        throw;
      }
    }

    public static object ExecuteScalar(……) { …… }
    public static void CacheParameters(……) { …… }
    public static SqlParameter[] GetCachedParameters(……) { …… }

    private static void PrepareCommand(SqlCommand cmd, SqlConnection conn, SqlTransaction trans, CommandType cmdType, string cmdText, SqlParameter[] cmdParms) {

      if (conn.State != ConnectionState.Open)
        conn.Open();

      cmd.Connection = conn;
      cmd.CommandText = cmdText;

      if (trans != null)
        cmd.Transaction = trans;

      cmd.CommandType = cmdType;

      if (cmdParms != null) {
        foreach (SqlParameter parm in cmdParms)
          cmd.Parameters.Add(parm);
      }
    }
  }
}
SQLServer / SQLHelper.csの一部
このファイルのフルセットは「Data Access Application Block for .NET」として公開されている。

 SQLHelper.csのコードは、アプリケーションによらずどんなアプリケーションにでも単独で使える便利なメソッド集である。

 以上の解説で、PetShopで用いられているデータベース・アクセスの実装のパターンを把握していただけただろうか。PetShopにはここで解説したこと以外の機能も多く実装されている。それでいて、本格的なサンプル・アプリケーションとしてはそれほどコード量は多くないので、ぜひ実際にダウンロードしてソース・コードを追いかけてみてほしい。End of Article

 

 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 記事ランキング

本日 月間