SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

.NET データ処理に役立つ26のヒント(後編)

.NETにおけるデータ管理のテクニック

ヒント6:Generics名前空間のその他のクラス

 ここまでは、Visual Studio 2005の新しいListクラスについて説明してきました。ここでは、System.Collections.Generics名前空間で目を引くその他の3つのクラス、DictionarySortedDictionaryCollectionについて説明します。

 Visual Studio 2005には、Dictionaryという新しいクラスが追加されています。この抽象クラスを使うと、コレクションのキーと要素を対応付けることができます。.NET Framework 2.0の関数の中には、Dictioanryクラスを使用しているものもあります。その一例が、TCPチャネルを新規作成するための新しいオーバーロードです。次の例では、新しいDictionaryオブジェクトを作成する際に、キーと値の両方が文字列であることを指定しています。

// Create a new dictionary object with two strings
Dictionary<string, string> oDict = new Dictionary<string, string>();
oDict.Add("secure", "true");
oDict.Add("password", "kevin");
TcpChannel oChannel = new TcpChannel(oDict, null, null);

 ディクショナリのエントリをキーによって並べ替える必要がある場合は、キーによる並べ替え順序が維持される、新しいSortedDictionaryクラスを使用するのがよいでしょう。

 また、ここまでは、新しいListクラスを使用してきましたが、Visual Studio 2005には、軽量なCollectionクラスもあり、並べ替え機能やフィルタ機能が必要ない単純なリストの場合にはそちらを使用できます。

Collection<int> oCol = new Collection<int>();
oCol.Add(2);
oCol.Add(3);
oCol.Insert(0,1);

 Collectionオブジェクトにはカスタムクラスも格納できます。

Collection<BaseballClass> oBaseballCollection = 
    new Collection<BaseballClass>();
oBaseballCollection.Add(new BaseballClass("Tom Glavine",
                                          "Mets"));
oBaseballCollection.Add(new BaseballClass("Derek Jeter",
                                          "Yankees"));
foreach (BaseballClass oBaseball in 
    oBaseballCollection)
MessageBox.Show(oBaseball.ToString());

 また、.NETのジェネリックには、リンクリストデータを扱うためのLinkedListクラスやLinkedListNoteクラスなどのほか、Queueクラス、Stackクラスもあります。

ヒント7:.NETのジェネリックを使用して型指定されたデータセットにレコードを読み込むデータアクセスクラスの作成

 私はストアドプロシージャと型指定されたデータセットを多用します。私にとって、大いなる目標の1つだったのが、型指定されたデータセットに対して、ストアドプロシージャから直接レコードを読み込むということでした。

 長いこと私が用いてきたのは、データアクセスクラスのベースメソッドを使用して、パラメータを持つストアドプロシージャから普通のデータセットにレコードを読み込むという方法でした。そのデータセットを、型指定されたデータセットに後でマージします。その方法でも確かに動作しますが、余分なコードと余分な処理が必要です。私がしたかったのは、型指定されたデータセットのインスタンスをベースメソッドに渡すと、そのベースメソッドがファクトリの役割を果たし、中身がセットされたデータセットが返ってくる、という方法でした。

 .NETのジェネリックを利用すると、そのようなクラスを作成し、使用することができます(リスト4とリスト5を参照)。そのようなクラスを作成するには、次の手順に従います。

  • 型指定されたデータセットのインスタンスと、データアクセスクラスのインスタンスを作成します(リスト5を参照)。
  • 型指定されたListを作成し、ストアドプロシージャで使用するSQLパラメータを格納します(ArrayListは使用しません)。
  • データアクセスクラスのメソッド(ReadIntoDs)を呼び出し、型指定されたデータセットのインスタンス、ストアドプロシージャの名前、ストアドプロシージャのパラメータが格納された型指定Listを渡します。
  • データアクセスメソッドReadIntoDsの本体を作成します(リスト5を参照)。第1パラメータと戻り値には、型指定されたプレースホルダを指定します。このパラメータにはデータセットのみを使用できるように指定しています。メソッド内のコードでデータセット固有のプロパティやメソッドを使用するからです。
  • public T ReadIntoDS<T>
          (T dsTypedDs, string cStoredProc, 
          List<SqlParameter> oParmList) 
       where T : DataSet
    
  • 標準のSqlConnectionオブジェクトやSqlDataAdapterなどを定義します。
  • この部分は力技です。SQL Serverから返るストアドプロシージャの結果セットでは、Table1、Table2、といった名前が使われています。一方、型指定されたデータセットを自分でデザインするときには、もっとわかりやすい名前(dtClientdtDetailsなど)を使用する可能性があります。したがって、Table、Table1といった名前を、型指定されたデータセットの名前に対応付ける必要があります。それには、DataAdapterTableMappingsを使用します。
  • DataAdapterからデータセットにレコードを読み込み、返します。
リスト4 ジェネリックデータアクセスメソッド
public class SimpleDataAccess
{
    // Pass the following:
    // 1) An instance of a typed dataset you wish to fill
    // 2) The name of the stored procedure
    // 3) A List of SqlParameters 
    // Function will execute the stored procedure,  
    // fill the typed dataset with the results, and then return it
    public T ReadIntoDs<T> 
            (T oTypedDs, string cSP, List<SqlParameter> oParms) 
        where T:DataSet
    {
        SqlConnection oSqlConn = this.GetConnection();
        SqlDataAdapter oSqlAdapt = new SqlDataAdapter(cSP, oSqlConn);
        oSqlAdapt.SelectCommand.CommandType = 
        CommandType.StoredProcedure;
        foreach (SqlParameter oParm in oParmList)
            oSqlAdapter.SelectCommand.Parameters.Add(oParm);

        // A little bit of "elbow grease…
        // SQL Server returns tablenames as "Table", "Table1", etc
        // We need to map in the tablenames from the typed DS
        // So loop through the tables in the Typed DS, get the name,
        // and map it to the corresponding table that SQL will
        // use as the default name
        int nTableCtr = 0;
        foreach (DataTable Dt in dsTypedDs.Tables) {
            string cSource = "";   
            if (nTableCtr == 0)
                cSource = "Table";
            else
                cSource = "Table" + nTableCtr.ToString().Trim();
        oSqlAdapter.TableMappings.Add(
            cSource, Dt.TableName.ToString());
        nTableCtr++;
    }
        // End of "elbow grease" - we can fill the dataset
        // from the adapter, now that we've mapped our tablenames
        oSqlAdapter.Fill(dsTypedDs);
        return dsTypedDs;
    }

    public SqlConnection GetConnection() 
    {
        // New SqlConnection StringBuilder class
        SqlConnectionStringBuilder oStringBuilder = 
            new SqlConnectionStringBuilder();
        oStringBuilder.UserID = "UserID";
        oStringBuilder.Password = "PassWord";
        oStringBuilder.InitialCatalog = "InitialCatalog";
        oStringBuilder.DataSource = "DataSource";
        return new SqlConnection(oStringBuilder.ConnectionString);
    }
}
リスト5 リスト4のジェネリックデータアクセスメソッドの使用例
// Create an instance of a typed DataSet
dsAgingReport odsAgingReport = new dsAgingReport();

// Create an instance of our Data Access Method
SimpleDataAccess oDataAccess = new SimpleDataAccess();

// Use the list class to create a collection of sql parameters
List<SqlParameter> oParms = new List<SqlParameter>();
oParms.Add(new SqlParameter("@dAgingDate", DateTime.Today));
oParms.Add(new SqlParameter("@lShowDetails", true));

// Call ReadIntoDs, passing the typed DS, name of the stored proc
// and the list of parameters
odsAgingReport = oDataAccess.ReadIntoDs(odsAgingReport,
   "[dbo].[GetAgingReceivables]",oParms);

ヒント8:ASP.NET 2.0のObjectDataSourceの概要

 本記事の前編で、ASP.NET 2.0のGridViewについて取り上げ、データセットにバインドする方法や、並べ替えとページングの処理方法について解説しました。もう1つ使用できるのが、ASP.NET 2.0のObjectDataSourceです。データを処理するビジネスオブジェクト/クラスを、GridViewなどのデータバインドコントロールに対して公開できます。

 ここでは、ObjectDataSourceの使用方法について、ステップバイステップ方式で解説します。最初の例では、「保留」になっている注文が格納された、型指定されたデータセットを返すビジネスオブジェクトを作成します。その後で、GridViewを配置したWebページを作成し、そのGridViewの直接のDataSourceとして、前述のビジネスオブジェクトを指定します。

  1. 「bzOrders」という別個のプロジェクトを作成します。型指定された単純なデータセットdsOrdersと、レコードが読み込まれたdsOrdersのインスタンスを返すメソッドGetOrdersOnHoldを作成します。
  2. 新しいWebページプロジェクトを作成し、「bzOrders.dll」を参照として追加します(図1を参照)。
  3. 図1 ビジネスオブジェクトへの参照を追加し、ObjectDataSourceで使用する
    図1 ビジネスオブジェクトへの参照を追加し、ObjectDataSourceで使用する
  4. 新しいWebページで、ツールボックスからObjectDataSourceのインスタンスを作成します(図2を参照)。
  5. 図2 ObjectDataSourceのインスタンスをツールボックスからドラッグし、Webページにドロップする
    図2 ObjectDataSourceのインスタンスをツールボックスからドラッグし、Webページにドロップする
  6. 新しいObjectDataSourceを右クリックし、データソースを設定するオプションを選択します。[Configure Data Source]ダイアログボックスが表示されます(図3を参照)。データを提供するクラスとしてbzObjectsを選択します。
  7. 図3 新しいObjectDataSourceを右クリックしてビジネスオブジェクトを選択する
    図3 新しいObjectDataSourceを右クリックしてビジネスオブジェクトを選択する
  8. 次に、標準のSelectInsertUpdateDeleteの各操作に使用するメソッドをObjectDataSourceに対して指定します。この例では、Selectコマンドのみを指定し、GetOrdersOnHoldメソッドとします(図4を参照)。
  9. 図4 データを取得するためのビジネスオブジェクトのメソッドを選択する
    図4 データを取得するためのビジネスオブジェクトのメソッドを選択する
  10. Webページ上にGridViewを作成し、DataSourceIDプロパティをObjectDataSourceに設定します(図5を参照)。また、GridViewのその他のプロパティを図5のように設定します。並べ替えとページングを有効にするオプションも設定します。
  11. 図5 GridViewを作成し、DataSourceIDやその他のプロパティを設定する
    図5 GridViewを作成し、DataSourceIDやその他のプロパティを設定する
  12. この時点で、Webページは実際に動作します。しかし列のサイズや配置の設定、見出しのカスタマイズなどを行っておく方がよいかもしれません。GridViewのプロパティシートを表示し、Columnsコレクションを選択します。列/フィールドのデザイナが表示され(図6を参照)、GridViewをカスタマイズできます。
  13. 図6 選択したフィールドが既に確立されており、表示をカスタマイズできる
    図6 選択したフィールドが既に確立されており、表示をカスタマイズできる
  14. これで完成です。Webページを実行すると、図7のような結果になります。
  15. 図7 最終的な結果。コードなしで完成!
    図7 最終的な結果。コードなしで完成!
注記
 重要な補足を1つ。図7を見るとわかるように、このページには、別のページに移動するためのリンクが表示されています。また、列見出しは、クリックして並べ替えを実行できるようになっています。ObjectDataSourceにバインドすると、並べ替えとページングが自動的に処理されます。コードを追加する必要はありません。

 このヒントで紹介したのは、ObjectDataSourceクラスの機能のほんの一部です。ObjectDataSourceでは、次のような処理も実現できます。

  • パラメータを使用して単一の注文を取得するretrieveメソッドをビジネスオブジェクトに定義できます。そして、ObjectDataSourceのデザイナで、そのメソッドをretrieveメソッドとして指定し、ページコントロールの値、FormFieldの値、QueryString、またはSession変数をパラメータに指定できます。
  • 標準的なInsertUpdateDeleteの各機能を実行するメソッドをビジネスオブジェクトに定義できます。こちらも、ObjectDataSourceのデザイナで、メソッドの対応付けとパラメータを指定できます。

 それからもう1つ、ObjectDataSourceが返したデータを「捕捉」するにはどうすればいいのか、疑問に思う人もいるかもしれません。たとえば、グリッドのキャプションに行数を表示したい場合などです。そのときは、ObjectDataSourceのSelectedイベントを使用します。

protected void ObjectDataSource1_Selected(
        object sender, ObjectDataSourceStatusEventArgs e)
{
    bzOrders.dsOrders odsOrders = 
        (dsOrders)e.ReturnValue;
    int nRows = odsOrders.dtOrders.Rows.Count;
    this.grdOrdersOnHold.Caption = 
        "Number of rows: " + nRows.ToString();
}

次のページ
ヒント9:SQL ServerのCOALESCE関数の使用

この記事は参考になりましたか?

japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Kevin S. Goff(Kevin S. Goff)

.NET、Visual FoxPro、SQL Server、Crystal Reportsによる独自のWebソリューション/デスクトップソリューションを提供するコンサルティンググループ「Common Ground Solutions」の創業者兼主任コンサルタント。ソフトウェアアプリケーションの開発経...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/794 2006/12/22 00:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー