次の方法で共有


その他の DataTable 列を追加する (C#)

作成者: Scott Mitchell

PDF のダウンロード

型指定された DataSet を TableAdapter ウィザードを使って作成すると、対応する DataTable に、メイン データベース クエリで返された列が含まれます。 しかし、DataTable にさらに他の列を含める必要がある場合があります。 このチュートリアルでは、他の DataTable 列がさらに必要な場合にストアド プロシージャをお勧めする理由を説明します。

はじめに

型指定された DataSet に TableAdapter を追加するときは、対応する DataTable のスキーマが、TableAdapter のメイン クエリで特定されます。 たとえば、メイン クエリでデータ フィールド ABC が返される場合、DataTable に、対応する列が 3 つ含まれます (それらの名前は、ABC)。TableAdapter には、そのメイン クエリに加え、他のクエリ (パラメーターに基づいてデータのサブセットなどを返す) を含めることができます。 たとえば、ProductsTableAdapter のメイン クエリ (すべての製品に関する情報を返す) に加え、指定されたパラメーターに基づいて特定の製品情報を返す GetProductsByCategoryID(categoryID)GetProductByProductID(productID) などのメソッドも含まれている場合があります。

DataTable のスキーマに TableAdapter のメイン クエリを反映するモデルは、TableAdapter のメソッドすべてで、返すデータ フィールドが、メイン クエリで指定されているのと同じかそれより少ない場合に適切に機能します。 1 つの TableAdapter メソッドでさらに他のデータ フィールドを返す必要がある場合は、それに応じて DataTable のスキーマを拡張する必要があります。 「マスター レコードの箇条書きと詳細 DataList を使用してマスター/詳細を表示する」チュートリアルでは、CategoriesTableAdapter に、メイン クエリで定義されている CategoryIDCategoryNameDescription データ フィールドに加えて NumberOfProducts (各カテゴリに関連付けられている製品の数をレポートするデータ フィールド) を返すメソッドを追加しました。 この新しいメソッドから NumberOfProducts データ フィールド値をキャプチャするために、手動で CategoriesDataTable に新しい列を追加しました。

ファイルのアップロード」チュートリアルで説明したように、アドホック SQL ステートメントを使う、データ フィールドがメイン クエリと正確に一致しないメソッドがある TableAdapter には、よく注意する必要があります。 TableAdapter 構成ウィザードを再実行すると、TableAdapter のすべてのメソッドが更新されて、それらのデータ フィールド リストがメイン クエリと一致するようになります。 その結果、列リストがカスタマイズされているメソッドは、メイン クエリの列リストに戻り、必要なデータを返さなくなります。 この問題は、ストアド プロシージャを使う場合には発生しません。

このチュートリアルでは、DataTable のスキーマを拡張して他の列をさらに含める方法について説明します。 アドホック SQL ステートメントを使う場合は TableAdapter が脆弱になるため、このチュートリアルではストアド プロシージャを使います。 ストアド プロシージャを使うように TableAdapter を構成する方法について詳しくは、「型指定された DataSet の TableAdapters に新しいストアド プロシージャを作成する」チュートリアルをご覧ください。

ステップ 1: PriceQuartile 列を ProductsDataTable に追加する

「型指定された DataSet の TableAdapters に新しいストアド プロシージャを作成する」チュートリアルでは、NorthwindWithSprocs という名前の型指定された DataSet を作成しました。 この DataSet には、現在、ProductsDataTableEmployeesDataTable という 2 つの DataTable が含まれています。 ProductsTableAdapter には次の 3 つのメソッドがあります:

  • GetProducts: メイン クエリ。Products テーブルからすべてのレコードを返します
  • GetProductsByCategoryID(categoryID): 指定された categoryID を持つすべての製品を返します。
  • GetProductByProductID(productID): 指定された productID を持つ特定の製品を返します。

メイン クエリと他の 2 つのメソッドはすべて、同じ一連のデータ フィールド、つまり Products テーブル内のすべての列を返します。 Categories または Suppliers テーブルから関連データをプルする、関連するサブクエリや JOIN はありません。 したがって、ProductsDataTable には、Products テーブル内の各フィールドに対応する列があります。

このチュートリアルでは、ProductsTableAdapter に、すべての製品を返す GetProductsWithPriceQuartile という名前のメソッドを追加します。 標準の製品データ フィールドに加え、GetProductsWithPriceQuartile には、製品価格がどの四分位内かを示す PriceQuartile データ フィールドも含まれます。 たとえば、価格が最上位 25% 以内の製品は PriceQuartile の値が 1 になり、価格が下位 25% 以内の製品は値が 4 になります。 しかし、この情報を返すストアド プロシージャの作成について考える前に、まず ProductsDataTable を更新して、GetProductsWithPriceQuartile メソッドの使用時に PriceQuartile の結果を保持するための列を含める必要があります。

NorthwindWithSprocs DataSet を開き、ProductsDataTable を右クリックします。 コンテキスト メニューから [追加] を選択し、[列] を選択します。

Add a New Column to the ProductsDataTable

図 1: ProductsDataTable に新しい列を追加する (クリックするとフルサイズの画像が表示されます)

これにより、DataTable に、型が System.String の Column1 という名前の新しい列が追加されます。 この列の名前を PriceQuartile にし、その型を System.Int32 に更新する必要があります (1 から 4 までの数値を保持するのに使うため)。 ProductsDataTable にある新しく追加した列を選択し、プロパティ ウィンドウで、Name プロパティを PriceQuartile に、DataType プロパティを System.Int32 に.設定します。

Set the New Column s Name and DataType Properties

図 2: 新しい列の Name および DataType プロパティを設定する (クリックするとフルサイズの画像が表示されます)

図 2 に示すように、列の値を一意にする必要があるかどうか、列が自動インクリメント列かどうか、データベースの NULL 値が許可されるかどうかなど、設定できるその他のプロパティがあります。 これらの値は既定値のままにします。

ステップ 2: GetProductsWithPriceQuartile メソッドを作成する

ProductsDataTable を更新して PriceQuartile 列を含めたので、これで、GetProductsWithPriceQuartile メソッドを作成する準備ができました。 まず、TableAdapter を右クリックし、コンテキスト メニューから [クエリの追加] を選択します。 これにより、TableAdapter クエリ構成ウィザードが起動されます。最初に、アドホック SQL ステートメントを使うか新規または既存のストアド プロシージャを使うかを確認するダイアログが表示されます。 価格四分位データを返すストアド プロシージャがまだないため、TableAdapter でこのストアド プロシージャを作成できるようにしましょう。 [新しいストアド プロシージャの作成] オプションを選択し、[次へ] をクリックします。

Instruct the TableAdapter Wizard to Create the Stored Procedure For Us

図 3: ストアド プロシージャを作成するように TableAdapter ウィザードに指示する (クリックするとフルサイズの画像が表示されます)

図 4 に示す後続の画面では、このウィザードで、追加するクエリの種類を確認されます。 GetProductsWithPriceQuartile メソッドでは Products テーブル内のすべての列とレコードが返されるため、[複数行を返す SELECT] オプションを選択し、[次へ] をクリックします。

Our Query will be a SELECT Statement that Returns Multiple Rows

図 4: クエリが、複数行を返す SELECT になる (クリックするとフルサイズの画像が表示されます)

次に、SELECT クエリの入力を求められます。 ウィザードに次のクエリを入力します:

SELECT ProductID, ProductName, SupplierID, CategoryID, 
       QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
       ReorderLevel, Discontinued,
       NTILE(4) OVER (ORDER BY UnitPrice DESC) as PriceQuartile
FROM Products

上記のクエリでは、SQL Server 2005 の新しい NTILE 関数を使って結果が 4 つのグループに分けられ、グループは、降順で並べ替えられた UnitPrice 値で決定されます。

残念ながら、クエリ ビルダーでは、OVER キーワードの解析方法がわからないため、上記のクエリを解析するときにエラーが表示されます。 そのため、クエリ ビルダーを使わずに、このウィザードで上記のクエリをテキスト ボックスに直接入力します。

Note

NTILE および SQL Server 2005 のその他の順位付け関数について詳しくは、SQL Server 2005 オンライン ブックで、「ROW_NUMBER (Transact-SQL)」と順位付け関数に関するセクションをご覧ください。

SELECT クエリを入力して [次へ] をクリックすると、ウィザードで、作成するストアド プロシージャの名前を指定するよう求められます。 新しいストアド プロシージャに Products_SelectWithPriceQuartile という名前を付け、[次へ] をクリックします。

Name the Stored Procedure Products_SelectWithPriceQuartile

図 5: ストアド プロシージャに Products_SelectWithPriceQuartile という名前を付ける (クリックするとフルサイズの画像が表示されます)

最後に、TableAdapter メソッドに名前を付けるよう求められます。 [DataTable にデータを格納する] および [DataTable を返す] チェック ボックスを両方ともそのままにし、それらのメソッドの名前を FillWithPriceQuartileGetProductsWithPriceQuartile にします。

Name the TableAdapter s Methods and Click Finish

図 6: TableAdapter のメソッドに名前を付けて [完了] をクリックする (クリックするとフルサイズの画像が表示されます)

SELECT クエリを指定し、ストアド プロシージャと TableAdapter メソッドに名前を付けたら、[完了] をクリックしてウィザードを完了します。 この時点で、ウィザードで、OVER SQL コンストラクトまたはステートメントがサポートされていないことを示す警告が 1 つか 2 つ表示される場合があります。 これらの警告は無視してかまいません。

ウィザードの完了後は、TableAdapter に FillWithPriceQuartile および GetProductsWithPriceQuartile メソッドが含まれておりデータベースに Products_SelectWithPriceQuartile という名前のストアド プロシージャが含まれている必要があります。 この新しいメソッドが実際に TableAdapter に含まれていることと、このストアド プロシージャがデータベースに正しく追加されていることを確認します。 データベースを確認したときに、このストアド プロシージャが表示されない場合は、[ストアド プロシージャ] フォルダーを右クリックし、[最新の情報に更新] を選択してみてください。

Verify that a New Method Has Been Added to the TableAdapter

図 7: TableAdapter に新しいメソッドが追加されていることを確認する

Ensure that the Database Contains the Products_SelectWithPriceQuartile Stored Procedure

図 8: データベースに Products_SelectWithPriceQuartile ストアド プロシージャが含まれていることを確認する (クリックするとフルサイズの画像が表示されます)

Note

アドホック SQL ステートメントの代わりにストアド プロシージャを使う利点の 1 つは、TableAdapter 構成ウィザードの再実行でストアド プロシージャの列リストが変更されないことです。 これを確認するには、TableAdapter を右クリックし、コンテキスト メニューから [構成] オプションを選択してウィザードを開始し、[完了] をクリックしてそれを完了します。 次に、データベースに移動し、Products_SelectWithPriceQuartile ストアド プロシージャを表示します。 その列リストが変更されていないことに注目してください。 アドホック SQL ステートメントを使っていた場合は、TableAdapter 構成ウィザードを再実行すると、このクエリの列リストがメイン クエリの列リストと一致するように元に戻されます。それにより、GetProductsWithPriceQuartile メソッドで使用されるクエリから NTILE ステートメントが削除されます。

データ アクセス層の GetProductsWithPriceQuartile メソッドが呼び出されると、TableAdapter で Products_SelectWithPriceQuartile ストアド プロシージャが実行され、返されたレコードごとに 1 行が ProductsDataTable に追加されます。 ストアド プロシージャで返されたデータ フィールドは、ProductsDataTable の列にマップされます。 ストアド プロシージャから返された PriceQuartile データ フィールドがあるため、その値は ProductsDataTablePriceQuartile 列に割り当てられています。

クエリで PriceQuartile データ フィールドが返されない TableAdapter メソッドの場合、PriceQuartile 列の値は、その DefaultValue プロパティで指定された値になります。 図 2 に示すように、この値は、既定値である DBNull に設定されています。 別の既定値を使う場合は、それに応じて DefaultValue プロパティを設定します。 列の DataType で指定されている DefaultValue 値が有効であることを確認してください (つまり、PriceQuartile 列の場合は System.Int32)。

この時点で、DataTable に他の列を追加するために必要な手順は実行済みです。 この追加の列が想定どおりに機能することを確認するために、各製品の名前、価格、価格四分位を表示する ASP.NET ページを作成しましょう。 しかしその前に、まず、DAL の GetProductsWithPriceQuartile メソッドを呼び出すメソッドを含むようにビジネス ロジック層 (BLL) を更新する必要があります。 次はステップ 3 で BLL を更新してから、ステップ 4 で ASP.NET ページを作成します。

ステップ 3: ビジネス ロジック層を拡張する

プレゼンテーション層からの新しい GetProductsWithPriceQuartile メソッドを使う前に、まず、対応するメソッドを BLL に追加する必要があります。 ProductsBLLWithSprocs クラス ファイルを開き、次のコードを追加します:

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Select, false)]
public NorthwindWithSprocs.ProductsDataTable GetProductsWithPriceQuartile()
{
    return Adapter.GetProductsWithPriceQuartile();
}

ProductsBLLWithSprocs での他のデータ取得メソッドと同様に、GetProductsWithPriceQuartile メソッドでは、DAL の対応する GetProductsWithPriceQuartile メソッドが呼び出され、その結果が返されます。

ステップ 4: ASP.NET Web ページで価格四分位情報を表示する

BLL への追加が完了したので、各製品の価格四分位を表示する ASP.NET ページの作成準備はできています。 AdvancedDAL フォルダー内の AddingColumns.aspx ページを開き、ツールボックスからデザイナーに GridView をドラッグして、その ID プロパティを Products に設定します。 GridView のスマート タグから、ProductsDataSource という名前の新しい ObjectDataSource にそれをバインドします。 ProductsBLLWithSprocs クラスの GetProductsWithPriceQuartile メソッドを使うように ObjectDataSource を構成します。 これは読み取り専用グリッドなので、[UPDATE]、[INSERT]、[DELETE] タブにあるドロップダウン リストを [(なし)] に設定します。

Configure the ObjectDataSource to Use the ProductsBLLWithSprocs Class

図 9: ProductsBLLWithSprocs クラスを使うように ObjectDataSource を構成する (クリックするとフルサイズの画像が表示されます)

Retrieve Product Information from the GetProductsWithPriceQuartile Method

図 10: GetProductsWithPriceQuartile メソッドから製品情報を取得する (クリックするとフルサイズの画像が表示されます)

データ ソース構成ウィザードを完了すると、Visual Studio で、メソッドで返された各データ フィールドの BoundField または CheckBoxField が GridView に自動的に追加されます。 これらのデータ フィールドの 1 つは、ステップ 1 で ProductsDataTable に追加した 列である PriceQuartile です。

GridView のフィールドを編集して、ProductNameUnitPricePriceQuartile BoundField を除くすべてを削除します。 値を通貨として書式設定するように UnitPrice BoundField を構成し、UnitPrice および PriceQuartile BoundField をそれぞれ右揃えと中央揃えにします。 最後に、残りの BoundField の HeaderText プロパティをそれぞれ Product、Price、Price Quartile に更新します。 また、GridView のスマート タグで [並べ替えを有効にする] チェック ボックスを選択します。

これらの変更の後は、GridView と ObjectDataSource の宣言型マークアップが次のようになります:

<asp:GridView ID="Products" runat="server" AllowSorting="True"
    AutoGenerateColumns="False" DataKeyNames="ProductID" 
    DataSourceID="ProductsDataSource">
    <Columns>
        <asp:BoundField DataField="ProductName" HeaderText="Product" 
            SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}" 
            HeaderText="Price" HtmlEncode="False" 
            SortExpression="UnitPrice">
            <ItemStyle HorizontalAlign="Right" />
        </asp:BoundField>
        <asp:BoundField DataField="PriceQuartile" HeaderText="Price Quartile" 
            SortExpression="PriceQuartile">
            <ItemStyle HorizontalAlign="Center" />
        </asp:BoundField>
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetProductsWithPriceQuartile" 
    TypeName="ProductsBLLWithSprocs">
</asp:ObjectDataSource>

図 11 に、ブラウザーからアクセスしたときのこのページを示します。 最初は製品が価格を基準に降順で並べ替えられており、各製品に適切な PriceQuartile 値が割り当てられていることに注目してください。 もちろん、このデータを、価格についての製品のランキングが反映されたまま、他の基準 ([Price Quartile] 列の値) で並べ替えることができます (図 12 を参照)。

The Products are Ordered by their Prices

図 11: 製品が価格を基準にして並べ替えられている (クリックするとフルサイズの画像が表示されます)

The Products are Ordered by their Names

図 12: 製品が名前を基準にして並べ替えられている (クリックするとフルサイズの画像が表示されます)

Note

数行のコードにより、GridView を拡張して、PriceQuartile 値に基づいて製品の行に色を付けることができます。 製品に、第 1 四分位内の場合は薄い緑色、第 2 四分位内の場合は薄い黄色などと色を付けることができます。 この機能を追加することをお勧めします。 GridView の書式設定について更新機能が必要な場合は、「データに基づくカスタム書式設定」チュートリアルをご覧ください。

代替方法 - 別の TableAdapter を作成する

このチュートリアルで説明したように、メイン クエリで示されている以外のデータ フィールドを返すメソッドを TableAdapter に追加するときに、対応する列を DataTable に追加できます。 ただし、このような方法が有効なのは、異なるデータ フィールドを返すメソッドが TableAdapter 内に少なく、そのような別のデータ フィールドがメイン クエリとあまり違わない場合のみです。

DataTable に列を追加するのではなく、最初の TableAdapter にあるメソッド (異なるデータ フィールドを返す) を含む、別の TableAdapter を DataSet に追加できます。 このチュートリアルでは、PriceQuartile 列を ProductsDataTable に追加するのではなく (これは GetProductsWithPriceQuartile メソッドでのみ使われる)、Products_SelectWithPriceQuartile ストアド プロシージャをメイン クエリとして使った ProductsWithPriceQuartileTableAdapter という名前の TableAdapter を DataSet に追加しました。 ASP.NET ページで、価格四分位を含む製品情報を取得する必要がある場合は ProductsWithPriceQuartileTableAdapter を使い、そうでない場合は、ProductsTableAdapter を使い続けることができます。

新しい TableAdapter を追加すると、DataTable はそのままで、それらの列に、それらの TableAdapter のメソッドで返されたデータ フィールドが正確に反映されます。 ただし、TableAdapter の追加により、同じタスクと機能を繰り返すことになる可能性があります。 たとえば、PriceQuartile 列が表示されている ASP.NET ページで、挿入、更新、削除をサポートする必要もある場合は、ProductsWithPriceQuartileTableAdapter で、その InsertCommandUpdateCommandDeleteCommand プロパティが適切に構成されている必要があります。 これらのプロパティには ProductsTableAdapter のプロパティが反映されますが、この構成では余分なステップが発生します。 また、データベースに対して製品を更新、削除、追加するための方法が、ProductsTableAdapter および ProductsWithPriceQuartileTableAdapter クラスの使用という 2 つになりました。

このチュートリアルのダウンロードでは、NorthwindWithSprocs DataSet 内に、この代替方法を示す ProductsWithPriceQuartileTableAdapter クラスが含まれています。

まとめ

ほとんどのシナリオでは、TableAdapter 内のメソッドすべてで同じ一連のデータ フィールドが返されますが、特定または 2 つのメソッドで他のフィールドを返す必要がある場合があります。 たとえば、「マスター レコードの箇条書きと詳細 DataList を使用してマスター/詳細を表示する」チュートリアルでは、CategoriesTableAdapter に、メイン クエリのデータ フィールドに加え、各カテゴリに関連付けられている製品の数をレポートする NumberOfProducts フィールドを返すメソッドを追加しました。 このチュートリアルでは、メイン クエリのデータ フィールドに加えて PriceQuartile フィールドを返すメソッドを ProductsTableAdapter 内に追加する方法について説明しました。 TableAdapter のメソッドで返された追加のデータ フィールドをキャプチャするには、対応する列を DataTable に追加する必要があります。

DataTable に列を手動で追加する予定の場合は、TableAdapter でストアド プロシージャを使うことをお勧めします。 TableAdapter でアドホック SQL ステートメントが使われている場合は、TableAdapter 構成ウィザードが実行されるたびに、すべてのメソッドのデータ フィールド リストが、メイン クエリで返されたデータ フィールドに戻ります。 ストアド プロシージャの場合はこの問題が発生しないため、それらをこのチュートリアルで使い、お勧めしました。

プログラミングに満足!

著者について

7 冊の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジに取り組んでいます。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズは24時間で2.0 ASP.NET 自分自身を教えています。 にアクセスするか、ブログを使用して にアクセスmitchell@4GuysFromRolla.comできます。これは でhttp://ScottOnWriting.NET見つけることができます。

特別な感謝

このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は、Randy Schmidt、Jacky Goor、Bernadette Leigh、Hilton Giesenow でした。 今後の MSDN の記事を確認することに関心がありますか? その場合は、 にmitchell@4GuysFromRolla.com行をドロップしてください。