SHOEISHA iD

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

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

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

japan.internet.com翻訳記事

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

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

ヒント4:データのフィルタリング

 ADO.NETでデータをフィルタ(抽出)する方法は2つあります。1つはDataViewとRowFilterを使う方法、もう1つはDataTable.Select()を使う方法です。.NET開発に不慣れな人から、どちらの方法を使うのが良いかという質問を受けることがあります。その答えは、状況に応じて変わります。その点を見ていくことにしましょう。

 一般的には、DataViewを使用して、フィルタした結果をバインドします。そして、DataRowの配列を使用して、フィルタした結果をたどり、処理や計算などを実行します。そもそも、DataViewとは、特定のフィルタと並べ替え順序が適用された、DataTableのビューの一つにすぎません。次のコードは、さまざまなフィルタや並べ替えの例です。

string cFilter;     // Examples of RowFilter
cFilter = " Amount > 1000 ";
cFilter = "FirstName = 'Ken' OR EmpFlag = true";
cFilter = " City LIKE '%whatever%' ";
cFilter = "EmployeeID IN (12,144,54)";
// This assumes a Parent Relation
cFilter = "Parent(RelName) = 'National'";
string cSort = "Location ASC, Salary DESC";
DataView Dv = new DataView(MyTable, cFilter,
    cSort, DataViewRowState.CurrentRows);

 上記のコードでは、DataViewのオーバーロードの1つを使用して、フィルタと並べ替えをまとめて指定しています。開発者によっては、DataTableだけを指定するオーバーロードを使用し、後続のコードでRowFilterプロパティとSortプロパティを設定するという方法を用いる場合もあります。実のところ、その方法では効率が下がり、無駄な処理が余分に加わることになります。1つの呼び出しにする方が良いでしょう。また、上記の例の中には、親リレーションを使用しているものがあります。DataRelationが定義されており、関連付けられた親(または子)の行に基づいてフィルタを実行したい場合には、Parent(またはChild)キーワードとDataRelationの名前を指定します。

 それともう1点、DataViewは、同じDataTableに対して複数作成でき、それぞれ別個のフィルタと並べ替えを適用できます。一方、DataTable.Select()では、DataRowオブジェクトのコレクションが結果として得られます。フィルタと並べ替えの構文は、DataViewの場合と同じものが使用できます。

DataRow[] aRows = MyTable.Select(cFilter,cSort);

 それでは、DataViewを使用するか否かはどのように判断すればよいのでしょうか。答えは簡単です。フィルタの結果をバインドしたいときにはDataViewを使用します。DataViewは、「IEnumerable」「ICollection」「IList」を実装しており、データバインドに最適です。DataTable.Select()が返すDataRowのコレクションはバインドできません。

 しかしその一方で、DataRowのコレクションでは可能なのに、DataViewでは不可能な処理もあります。型指定されたデータセットの中の、厳密に型指定されたオブジェクトのいずれかとして、各行をキャストするという処理です。

dsOrders odsOrder = new dsOrders();

// Run some process to populate orders
// Now perform a select and filter
DataRow[] aRows =
    odsOrder.dtOrderHdr.Select(cFilter, cOrder);

// We can cast the collection of rows
// as the strongly-typed rows from our typed DS
foreach (dsOrders.dtOrderHdrRow oRow in aRows)
{
    cOrderNumber = oHeaderRow.OrderNumber;
}

 従って、一般論としては、フィルタしたデータをバインドする場合にはDataViewを使用し、各行をたどって計算などの処理を実行する場合には行の配列を使用するのが良いでしょう。

 時として、DataViewをDataTableにコピーし戻すことが必要になる場合があります。DataViewをXMLにコピーすることや、DataViewを認識しない.NETライブラリや製品(Crystal Reportsなど)にDataViewの結果をバインドすることが必要になるかもしれません。Visual Studio .NET 2003には、DataViewをDataTableに変換する機能は備わっていませんが、幸い、小粒ながらも便利な汎用的関数を作成することで、その処理を実現できます。

public DataTable ViewToTable(DataView dv)
{
    // Create a new table structure from the table
    // object of the view, then loop through the view
    // and import the rows into the new table
    DataTable DtReturn = dv.Table.Clone();
    foreach (DataRowView drv in dv) DtReturn.ImportRow(drv.Row);
    // Note that we have to use ImportRow
    // There's no such thing as Row.Copy
    return DtReturn;
}

 このコードに手を加えれば、DataRowの配列からDataTableを作成する処理も簡単に実現できます。

 最後にもう1つ、重要な情報です。Visual Studio 2005には、ToTable()という便利なADO.NET関数が新たに用意されています。DataViewをDataTableに変換する関数です。

DataTable dtFromView = dv.ToTable();

 ToTableには、個別の値ごとにフィルタを実行したい開発者に朗報となる機能も備わっています。Visual Studio 2003で開発者からよく挙がっていたのが、ADO.NETにはSQLのSELECT DISTINCTに相当する機能はあるかという質問でした。Visual Studio 2003では、その機能はネイティブには備わっていなかったため、その機能はなしで我慢するか、その処理を実現する独自のコードを作成するかのいずれかの方法しかありませんでした。ToTableはオーバーロードされており、SELECT DISTINCTステートメントと同じような形で列のリストを指定できます。

bool lDistinct = true;
DataTable dtFromView =
    dv.ToTable(lDistinct, "Column1", "Column2");

// You can even create a unique list from the
// DefaultViewof a DataTable
DataTable dtUnique =
    dtMyTable.DefaultView.ToTable(true, "Column1", "Column2");

ヒント5:DataSetでの演算

 データセットの演算は2つのレベルで実装できます。1つは行ごとの演算で、その場合は集計列としてDataColumnを定義します。もう1つはDataTable全体(または行のコレクション全体)を対象とした演算で、その場合は「SUM」または「COUNT」を計算します。

 集計列は次のように作成します。

string cExpr = "HourlyRate * Hours";
Dt.Columns.Add("Pay", typeof(Decimal), cExpr);

 型指定されたデータセットを使用している場合は、データセットデザイナでExpressionプロパティを設定することで集計列を定義できます。

 DataTableのすべての行に対する計算を実行する場合は、DataTable.Compute()メソッドを使用します。Computeが返すオブジェクトは、適切な型にキャストできます。

string cExpr = " SUM(Hours)";
string cCond = " OTFlag = true";
decimal nTotHrs =
    (decimal)Dt.Compute(cExpr,cCond);

 また、親子関係に基づく集計値を自動的に計算することもできます。例えば、顧客データのDataTableと注文データのDataTableがあり、顧客IDに基づく親子関係があるとします。この場合、顧客データのテーブル「dtClients」に、各顧客に対応する注文の合計を反映する集計列を持たせることができます。そのためには、親テーブルでSUM(Child.OrderAmount)という式を使用します。型指定されたデータセットを使用している場合には、Visual Studio 2005のデータセットデザイナでその式を直接指定できます。

次のページ
ヒント6:ASP.NET 2.0のGridViewの概要

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

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/759 2006/12/22 09:54

イベント

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

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

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

メールバックナンバー