ヒント6: データアクセス層の作成
ストアドプロシージャが完成したら、次に、ストアドプロシージャと連携するデータアクセスコンポーネントを構成します。
2006年9月/10月号の『CoDe Magazine』に掲載された「Baker's Dozen」の記事では、TableAdapterまたはDataSetのMerge関数を使わずに、.NETジェネリックを利用して、型指定されたDataSet(または標準のDataSet)を直接読み込む基本データアクセスクラスを取り上げました。開発者は、型指定されたDataSetのインスタンスに加えて、SQLパラメータのリストとストアドプロシージャの名前を渡すことができます。基本データアクセスクラスは、型指定されたDataSetを自動的に読み込みます(この記事のサンプルコードには、このメソッドが含まれています)。
リスト2には、基本DALを継承するDAL(daCustomer)が含まれています。メソッドGetCustomersは、次の処理を実行します。
- 表2にリストされているパラメータを受け取ります。
SQLパラメータのリストを作成します。- 各検索条件パラメータの長さをチェックし、文字列が空の場合はNULL値を渡します。
- 型指定されたDataSetのインスタンスを作成します(例では、単純な型指定のDataSetを使用しています)。
- 基本メソッド
ReadIntoTypedDsを呼び出します。
List<SqlParameter> oSQLParms = new List<SqlParameter>(); // set any parameters to NULL, if they are blank oSQLParms.Add(new SqlParameter("@LastName", LastName.Length > 0 ? LastName : null)); dsCustomer odsCustomer = new dsCustomer(); this.ReadIntoTypedDs(odsCustomer, "[dbo].[LookupEmployees]", oSQLParms); return odsCustomer;
ヒント7: 基本のASP.NET 2.0 Webページの作成
リスト3は、Webページの完全な分離ソースコードです(Default.aspx.cs)。このページには、ヒント6のデータアクセスクラスへの参照が含まれているため、開発者はDALを呼び出すことができます。コードの重要なポイントを次に示します。
- 1文字の英数字による「クイックナビ」用のドロップダウンリスト(
cboAlphaIndex)は、英数字値の配列から読み込まれます(詳細については、ヒント8を参照)。 - Retrieveボタン(
btnRetrieve)のClickイベントが、ページメソッドのGetDataを呼び出します。次にこれが、DALのGetCustomersメソッドを呼び出します。 - ページが
GetDataを呼び出すときはいつでも、SetInfoという名前のメソッドも呼び出します(このメソッドについてはヒント10で説明します)。このメソッドは結果セット内の行数を表示し、さらにセッション変数のCurrentFirstRowおよびCurrentLastRowを更新します。 - 4つのナビゲーションコマンドボタン(
btnFirst、btnPrev、btnNext、btnLast)は、4つのナビゲーションメソッドを呼び出します。これについては、ヒント8で説明します。 - GridView(
grdResults)には、ユーザーが列見出しをクリックするたびに起動するイベント(grdResults_Sorting)があります。詳細については、ヒント9で説明します。 - GridViewには、ユーザーがGridView内の行を選択すると起動するイベント(
grdResults_SelectedIndexChanged)もあります。ヒント11では、このイベントの処理方法と、GridViewのDataKeyNamesプロパティの定義済みの値(CustomerIDに設定)を使って行の値を決定する方法について説明します。
ヒント8: クイック検索ナビゲーションとページングの処理
ページのLoadイベントによって、ユーザーがクイックナビゲーション用に選択できる1文字値のドロップダウンリストが読み込まれます。
string[] alphabet = new string[] { " ", "A", "B", "C",..., "0", "1", "2", "3"...; for (int i = 0; i < alphabet.Length; i++) this.cboAlphaIndex.Items.Add(alphabet[i].Trim());
コードには、ナビゲーション用の4つのメソッドもあります。これは、4つのナビゲーションボタンのClickイベントに対応します。これらのメソッドは、ナビゲーションの方向に応じてStartRowIndexを設定します。
private void NavBegin() { // set the startrowindex to zero, and make sure // we're not specifying a letter Session["startRowIndex"] = 0; // set alpha index pulldown back to nothing this.cboAlphaIndex.SelectedIndex = 0; this.GetData(); } private void NavPrevious() { // set the startrowindex to the row number for the // first record in the current page, minus 1, and // minus maxrows // so if we're looking at rows 200-249, and we go // back one page, the new start row index would be // 200-1-50, or 149....and we'd get back 149-199 Session["startRowIndex"] = (int)Session["CurrentFirstRow"] - (int)Session["MaxRows"]; this.cboAlphaIndex.SelectedIndex = 0; this.GetData(); } private void NavNext() { // startrow index becomes the value of the last // row [the stored proc does a 'greater than'] Session["startRowIndex"] = (int)Session["CurrentLastRow"] + 1; this.cboAlphaIndex.SelectedIndex = 0; this.GetData(); } private void NavEnd() { // -1 is the 'magic number', it tells the stored // proc to just grab everything from // rowcount-maxrows, to rowcount Session["startRowIndex"] = -1; this.cboAlphaIndex.SelectedIndex = 0; this.GetData(); }
ヒント9: 列の並び替えの処理
列を並び替えるには、Sortingイベントを利用します。このイベントは、ユーザーが選択した列見出しのSortExpressionを公開します。SortExpressionをプログラムで明示的に設定しない場合、SortExpressionはデータ列の名前になります。
protected void grdResults_Sorting (object sender, GridViewSortEventArgs e) { Session["SortCol"] = e.SortExpression.ToString().Trim(); this.lblAlphaNav.Text = e.SortExpression.ToString().Trim() + " starting with..."; this.GetData(); }
ヒント10: グリッドの結果セット情報の表示
GetDataを呼び出して結果セットを返したら、結果セットをSetInfoに渡します。このメソッドでは、最初に、集計行を取り出します。これは、次に示すように、フィルタ条件を満たす行の総数に相当します。
using daCustomer; private void SetInfo(dsCustomer odsCustomer) { DataRow[] aRows = odsCustomer.dtCustomer.Select ("customerid = -1"); int nTotalCount = 0; if( aRows.Length> 0) { dsCustomer.dtCustomerRow oRow = (dsCustomer.dtCustomerRow)aRows[0]; nTotalCount = oRow.RowNum; oRow.Delete(); odsCustomer.dtCustomer.AcceptChanges(); } ...
SetInfoは、次に、実際に表示する行数を決定します。すべてではありませんが、ほとんどの場合、これはMaxRowsと同じになります。値が1以上の場合、メソッドは結果セットの先頭と末尾の行のRowNum列を読み取り、その値を、セッション変数のCurrentFirstRowおよびCurrentLastRowに割り当てます。
int nResultCount = odsCustomer.dtCustomer.Rows.Count; if (nResultCount > 0) { Session["CurrentFirstRow"] = odsCustomer.dtCustomer[0].RowNum; Session["CurrentLastRow"] = odsCustomer.dtCustomer [nResultCount - 1].RowNum; } this.grdResults.Caption = "Number of matching records: " + nTotalCount.ToString().Trim() + "...click on any column heading to sort";
ヒント11: 別のページにリンクする列の設定
ASP.NETの初心者がよく悩んでしまう問題の1つは、GridView内の各行に対してリンクを設定するにはどうすればいいかということです。また、図1、2、3に示されているような選択アイコンを各行に追加する方法も問題になります。
基本の3つの手順に従うだけで、これを実装できます。最初に、GridViewにバインドされている列のリストから、キーフィールドを特定する必要があります。これを行うには、GridViewのDataKeyNamesプロパティを設定します。キーフィールド(またはフィールドの組み合わせ)は、各行の一意な値を表している必要があります。サンプルプロジェクトではCustomerIDを一意なIDとして使っているため、開発者はGridViewの一意なIDを次のように定義できます。
// set the DataKeyNames property // to uniquely determine a selected row this.grdResults.DataKeyNames = new string[] { "CustomerID" };
次に、ButtonFieldオブジェクトを作成し、プロパティを設定し、オブジェクトをGridViewに追加することによってアイコン列を追加します。
// Insert a button field to the GridView // so that the user can select a row by clicking // on the button icon ButtonField obt = new ButtonField(); obt.CommandName = "Select"; obt.ButtonType = ButtonType.Image; obt.ImageUrl = "openfolder.ico"; this.grdResults.Columns.Clear(); this.grdResults.Columns.Add(obt);
最後に、ユーザーがアイコンをクリックすると起動するGridViewのSelectedIndexChangedイベントを利用します。イベントの中で、SelectedDataKeyプロパティの値をキーの有効な型に変換します。この例の場合は、現在の顧客IDの値を取得し、そのIDを使って、クエリ文字列が含まれる別のWebページへの呼び出しを設定します。
protected void grdResults_SelectedIndexChanged (object sender, EventArgs e) { // this reads from the DataKeyNames property int nCustomerID = (int)this.grdResults. SelectedDataKey.Values[0]; Response.Redirect("CustomerPage.aspx?CUSTID=" + nCustomerID.ToString().Trim()); }
