JOIN を使用するように TableAdapter を更新する (VB)

作成者: Scott Mitchell

PDF のダウンロード

データベースを操作する場合、複数のテーブルに分散するデータを要求することは一般的です。 2 つの異なるテーブルからデータを取得するには、相関サブクエリまたは JOIN 操作を使用します。 このチュートリアルでは、メイン クエリに JOIN を含む TableAdapter を作成する方法を確認する前に、相関サブクエリと JOIN 構文を比較します。

はじめに

リレーショナル データベースでは、操作する必要があるデータは、多くの場合、複数のテーブルに分散しています。 たとえば、製品情報を表示する場合は、各製品の対応するカテゴリと仕入先の名前を一覧表示する必要があります。 Products テーブルには CategoryIDSupplierID の値がありますが、実際のカテゴリ名と仕入先名はそれぞれ CategoriesSuppliers テーブルに含まれています。

別の関連テーブルから情報を取得するには、相関サブクエリまたは JOIN を使用します。 相関サブクエリは、外側のクエリの列を参照する入れ子になった SELECT クエリです。 たとえば、「データ アクセス層の作成」チュートリアルでは、ProductsTableAdapter のメイン クエリで 2 つの相関サブクエリを使用して、各製品のカテゴリ名と仕入先名を返しました。 JOIN は、2 つの異なるテーブルから関連する行をマージする SQL コンストラクトです。 「SqlDataSource コントロールを使用したデータのクエリ」のチュートリアルで、カテゴリ情報を各製品と共に表示するために JOIN を使用しました。

TableAdapters で JOIN を使用することを控えた理由は、TableAdapter のウィザードで対応する INSERTUPDATEDELETE の各ステートメントを自動生成するのに制限があるためです。 具体的には、TableAdapter のメイン クエリに JOIN が含まれている場合、TableAdapter は、アドホック SQL ステートメントまたはストアド プロシージャを、その InsertCommandUpdateCommand、および DeleteCommand プロパティに対して自動作成することはできません。

このチュートリアルでは、メイン クエリに JOIN を含む TableAdapter を作成する方法を説明する前に、相関サブクエリと JOIN を簡単に比較して対比ます。

相関サブクエリと JOIN の比較と対比

Northwind DataSet の最初のチュートリアルで作成された ProductsTableAdapter は、相関サブクエリを使用して、各製品の対応するカテゴリとサプライヤー名を取り戻していました。 ProductsTableAdapter のメイン クエリを下に示します。

SELECT ProductID, ProductName, SupplierID, CategoryID, 
       QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
       ReorderLevel, Discontinued,
       (SELECT CategoryName FROM Categories WHERE Categories.CategoryID = 
            Products.CategoryID) as CategoryName, 
       (SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = 
            Products.SupplierID) as SupplierName
FROM Products

2 つ相関サブクエリ ((SELECT CategoryName FROM Categories WHERE Categories.CategoryID = Products.CategoryID) および (SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = Products.SupplierID)) は、 外側の SELECT ステートメントの列リストの追加列として製品ごとに 1 つの値を返す SELECT クエリです。

または、JOIN を使用して、各製品のサプライヤーとカテゴリ名を返すことができます。 次のクエリは、上記と同じ出力を返しますが、サブクエリの代わりに JOIN を使用しています。

SELECT ProductID, ProductName, Products.SupplierID, Products.CategoryID, 
       QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
       ReorderLevel, Discontinued,
       Categories.CategoryName, 
       Suppliers.CompanyName as SupplierName
FROM Products
    LEFT JOIN Categories ON
        Categories.CategoryID = Products.CategoryID
    LEFT JOIN Suppliers ON
        Suppliers.SupplierID = Products.SupplierID

JOIN は、あるテーブルのレコードを、何らかの条件に基づいて別のテーブルのレコードとマージします。 たとえば、上のクエリの LEFT JOIN Categories ON Categories.CategoryID = Products.CategoryID では、各製品レコードを製品の CategoryID 値と一致する CategoryID 値を持つカテゴリ レコードとマージするように SQL Server に指示しています。 マージされた結果を使用すると、各製品の対応するカテゴリ フィールド (CategoryName など) を操作できます。

Note

JOIN は、リレーショナル データベースのデータに対してクエリを実行する場合に一般的に使用されます。 JOIN 構文を初めて使用する場合、またはその使用法を少しブラッシュアップする必要がある場合は、W3 SchoolsSQL Join チュートリアルをお勧めします。 また、SQL オンライン ブックの「JOIN の基礎」と「サブクエリの基礎」セクションも読むことをお勧めします。

JOIN と相関サブクエリの両方を使用して他のテーブルから関連データを取得できるため、多くの開発者はどちらの方法を使用するかについて頭を悩ませます。 私が話しを聞いたすべての SQL の達人は、ほぼ同じことを言っています。つまり、SQL Server はほぼ同じ実行計画を生成するため、パフォーマンスの面からはこれはあまり重要ではありません。 そうなると、彼らのお勧めは、あなたやあなたのチームが最も慣れている技術を使用することです。 これらの専門家はこのように勧めたうえで、すぐに相関サブクエリよりも JOIN を好むことを表明していたことに言及しておきたいと思います。

型指定された DataSets を使用してデータ アクセス層を構築する場合、サブクエリを使用したほうがツールが適切に機能します。 特に、TableAdapter のウィザードは、メイン クエリに JOIN が含まれている場合は、対応する INSERTUPDATEDELETE の各ステートメントを自動生成しませんが、相関サブクエリが使用されている場合は、これらのステートメントが自動生成されます。

この短所を確認するには、~/App_Code/DAL フォルダーに一時的な型指定された DataSet を作成します。 TableAdapter 構成ウィザードで、アドホック SQL ステートメントの使用を選択し、次の SELECT クエリを入力します (図 1 を参照)。

SELECT ProductID, ProductName, Products.SupplierID, Products.CategoryID, 
       QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
       ReorderLevel, Discontinued,
       Categories.CategoryName, 
       Suppliers.CompanyName as SupplierName
FROM Products
    LEFT JOIN Categories ON
        Categories.CategoryID = Products.CategoryID
    LEFT JOIN Suppliers ON
        Suppliers.SupplierID = Products.SupplierID

JOIN が含まれているクエリが入力された TableAdaptor 構成ウィザード ウィンドウを示すスクリーンショット。

図 1: JOIN を含むメイン クエリを入力します (フルサイズの画像を表示するにはクリックします)

既定では、TableAdapter は、メイン クエリに基づいて INSERTUPDATEDELETE の各ステートメントを自動的に作成します。 [詳細設定] ボタンをクリックすると、この機能が有効になっていることがわかります。 この設定にもかかわらず、TableAdapter は、メイン クエリに JOIN が含まれているため、INSERTUPDATEDELETE の各ステートメントを作成できません。

[Insert、Update、および Delete ステートメントの生成] チェック ボックスがオンの [詳細オプション] ウィンドウを示すスクリーンショット。

図 2: JOIN を含むメイン クエリを入力する

[完了] をクリックして、ウィザードを完了します。 この時点で、DataSet のデザイナーには、SELECT クエリの列リストで返される各フィールドの列を持つ DataTable を含む単一の TableAdapter が含まれます。 これには、図 3 に示すように、CategoryName および SupplierName が含まれます。

DataTable には、列リストで返される各フィールドの列が含まれている

図 3: DataTable には、列リストで返される各フィールドの列が含まれている

DataTable には適切な列が含まれていますが、TableAdapter には、その InsertCommandUpdateCommandDeleteCommand プロパティの値がありません。 これを確認するには、デザイナーで TableAdapter をクリックし、プロパティ ウィンドウに移動します。 ここで、InsertCommandUpdateCommand、および DeleteCommand プロパティが (なし) に設定されていることがわかります。

InsertCommand、UpdateCommand、DeleteCommand の各プロパティは

図 4: InsertCommandUpdateCommand、およびDeleteCommand プロパティが (なし) に設定されている (フルサイズの画像を表示するにはクリックします)

この欠点を回避するために、プロパティ ウィンドウを使って、InsertCommandUpdateCommandDeleteCommand プロパティの SQL ステートメントとパラメーターを手動で指定できます。 または、TableAdapter のメインクエリを JOIN を"含めない" ように構成することから始めることもできます。 これにより、INSERTUPDATE、および DELETE ステートメントが自動生成されるようになります。 ウィザードが完了したら、JOIN 構文が含まれるように、プロパティ ウィンドウから TableAdapter の SelectCommand を手動で更新できます。

この方法は機能しますが、アドホック SQL クエリを使用する場合は非常に不安定です。TableAdapter のメイン クエリがウィザードを通じて再構成されるたびに、自動生成された INSERTUPDATEDELETE の各ステートメントが再作成されるためです。 つまり、TableAdapter を右クリックし、コンテキスト メニューから [構成] を選択してウィザードをもう一度完了すると、後で行ったすべてのカスタマイズが失われます。

幸いなことに、TableAdapter の自動生成される INSERTUPDATEDELETE ステートメントの不安定さは、アドホック SQL ステートメントに限定されます。 TableAdapter でストアド プロシージャが使用されている場合は、ストアド プロシージャが変更されることを心配することなく、SelectCommandInsertCommandUpdateCommand、または DeleteCommand ストアド プロシージャをカスタマイズし、TableAdapter 構成ウィザードを再実行できます。

次のいくつかの手順で、TableAdapter を作成します。最初は、対応する挿入、更新、および削除のストアド プロシージャが自動生成されるように、JOIN を省略するメイン クエリを使用します。 次に、関連テーブルから追加の列を返す JOIN を使用するように SelectCommand を更新します。 最後に、対応する Business Logic Layer クラスを作成し、ASP.NET Web ページで TableAdapter を使用してデモンストレーションを実施します。

手順 1: 簡略化されたメイン クエリを使用して TableAdapter を作成する

このチュートリアルでは、NorthwindWithSprocs DataSet の Employees テーブルに TableAdapter と厳密に型指定された DataTable を追加します。 Employees テーブルには、従業員の上司の EmployeeID を指定した ReportsTo フィールドが含まれています。 たとえば、従業員 Anne Dodsworth の ReportTo の値は5 で、これは Steven Buchanan の EmployeeID です。 したがって、Anne の報告先は上司の Steven です。 各従業員の ReportsTo の値を報告するだけでなく、上司の名前を取得する必要もあります。 これは、JOIN を使用して実現できます。 ただし、最初に TableAdapter を作成するときに JOIN を使用すると、ウィザードで対応する挿入、更新、削除の機能が自動的に生成されなくなります。 そのため、まず、メイン クエリに JOIN が含まれていない TableAdapter を作成します。 その後、手順 2 で、メイン クエリのストアド プロシージャを更新して、JOIN を使って上司の名前を取得します。

まず、~/App_Code/DAL フォルダーの NorthwindWithSprocs DataSet を開きます。 デザイナーを右クリックし、コンテキスト メニューから [追加] オプションを選択し、[TableAdapter] メニュー項目を選択します。 これにより TableAdapter 構成ウィザードが起動します。 図 5 に示すように、ウィザードで新しいストアド プロシージャを作成することにし、[次へ] をクリックします。 TableAdapter ウィザードから新しいストアド プロシージャを作成する方法については、「型指定された DataSet の TableAdapter の新しいストアド プロシージャの作成」チュートリアルを参照してください。

[新しいストアド プロシージャの作成] オプションを選択する

図 5: [新しいストアド プロシージャの作成] オプションを選択する (フルサイズの画像を表示するにはクリックします)

TableAdapter の メイン クエリには、次の SELECT ステートメントを使用します。

SELECT EmployeeID, LastName, FirstName, Title, HireDate, ReportsTo, Country
FROM Employees

このクエリには JOIN が含まれていないため、TableAdapter ウィザードは、対応する INSERTUPDATEDELETE ステートメントを含むストアド プロシージャ、およびメイン クエリを実行するためのストアド プロシージャを自動的に作成します。

次の手順では、TableAdapter のストアド プロシージャに名前を付けることができます。 図 6 に示すように、名前 Employees_SelectEmployees_InsertEmployees_UpdateEmployees_Delete を使用します。

TableAdapter のストアド プロシージャに名前を付ける

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

最後の手順では、TableAdapter のメソッドに名前を付けるダイアログが表示されます。 メソッド名として FillGetEmployees を使用します。 また、[Create methods to send updates directly to the database (GenerateDBDirectMethods)] (更新を直接データベースに送信するためのメソッドを作成する (GenerateDBDirectMethods)) チェック ボックスはオンのままにしてください。

TableAdapter のメソッドに Fill と GetEmployees という名前を付ける

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

ウィザードが完了したら、少し時間を取ってデータベース内のストアド プロシージャを調べてみましょう。 Employees_SelectEmployees_InsertEmployees_UpdateEmployees_Delete の 4 つの新しいものが表示されます。 次に、作成したばかりの EmployeesDataTableEmployeesTableAdapter を調べます。 DataTable には、メイン クエリによって返される各フィールドの列が含まれています。 TableAdapter をクリックし、プロパティ ウィンドウに移動します。 ここでは、対応するストアド プロシージャを呼び出すために、InsertCommandUpdateCommand および DeleteCommand プロパティが正しく構成されていることがわかります。

TableAdapter には、挿入、更新、削除の機能が含まれている

図 8: TableAdapter に、挿入、更新、および削除の機能が含まれている (フルサイズの画像を表示するにはクリックします)

挿入、更新、削除のストアド プロシージャのが自動的に作成され、InsertCommandUpdateCommandDeleteCommand の各プロパティが正しく構成されたので、各従業員の上司に関する追加情報を返すように、SelectCommand ストアド プロシージャをカスタマイズする準備ができました。 具体的には、Employees_Select ストアド プロシージャを更新し、JOIN を使用して上司の FirstNameLastName の値を返す必要があります。 ストアド プロシージャを更新した後、これらの追加の列が含まれるように DataTable を更新する必要があります。 これら 2 つの作業については、手順 2 と手順 3 で取り上げます。

手順 2: ストアド プロシージャをカスタマイズして JOIN を含める

まず、サーバー エクスプローラーに移動し、Northwind データベースのストアド プロシージャ フォルダーをドリルダウンして、Employees_Select ストアド プロシージャを開きます。 このストアド プロシージャが表示されない場合は、[ストアド プロシージャ] フォルダーを右クリックし、[最新の情報に更新] を選択します。 ストアド プロシージャを更新して、LEFT JOIN を使用して上司の名と姓を返すようにします。

SELECT Employees.EmployeeID, Employees.LastName, 
       Employees.FirstName, Employees.Title, 
       Employees.HireDate, Employees.ReportsTo, 
       Employees.Country,
       Manager.FirstName as ManagerFirstName, 
       Manager.LastName as ManagerLastName
FROM Employees
    LEFT JOIN Employees AS Manager ON
        Employees.ReportsTo = Manager.EmployeeID

SELECT ステートメントを更新した後、[ファイル] メニューに移動し、[Employees_Select の保存] を選択して変更を保存します。 または、ツール バーの [保存] アイコンをクリックするか、Ctrl + S キーを押します。 変更を保存した後、サーバー エクスプローラーで Employees_Select ストアド プロシージャを右クリックし、[実行] を選択します。 これにより、ストアド プロシージャが実行され、その結果が [出力] ウィンドウに表示されます (図 9 を参照)。

ストアド プロシージャの結果が [出力] ウィンドウに表示される

図 9: 出力ウィンドウに表示されたストアド プロシージャの結果 (クリックするとフルサイズの画像が表示されます)

手順 3: DataTable の列を更新する

この時点で、Employees_Select ストアド プロシージャは ManagerFirstNameManagerLastName の値を返しますが、EmployeesDataTable にはこれらの列がありません。 これらの不足している列は、次の 2 つの方法のいずれかで DataTable に追加できます。

  • 手動 - DataSet デザイナーで DataTable を右クリックし、[追加] メニューから [列] を選択します。 その後、列に名前を付け、必要に応じてプロパティを設定できます。
  • 自動 - TableAdapter 構成ウィザードは、SelectCommand ストアド プロシージャによって返されるフィールドを反映するように DataTable の列を更新します。 アドホック SQL ステートメントを使用する場合、ウィザードは、InsertCommandUpdateCommandDeleteCommand プロパティも削除します。これは、SelectCommandJOIN が含まれるようになったためです。 ただし、ストアド プロシージャを使用する場合、これらのコマンド プロパティはそのままです。

前のチュートリアルでは、「マスター レコードの箇条書きと詳細 DataList を使用してマスター/詳細を表示する」および「ファイルのアップロード」を含む前のチュートリアルでは、DataTable の列を手動で追加する方法について説明しました。このプロセスについては、次のチュートリアルでもう一度詳しく説明します。 ただし、このチュートリアルでは、TableAdapter 構成ウィザードを使った自動アプローチを使用します。

まず、EmployeesTableAdapter を右クリックしてコンテキスト メニューから [構成] を選択します。 これにより、TableAdapter 構成ウィザードが表示され、選択、挿入、更新、削除に使用されるストアド プロシージャと、戻り値およびパラメーター (存在する場合) が一覧表示されます。 図 10 は、このウィザードを示しています。 ここで、Employees_Select ストアド プロシージャが ManagerFirstNameManagerLastName フィールドを返すようになったことがわかります。

Employees_Select ストアド プロシージャの更新された列リストがウィザードに表示される

図 10: ウィザードは、Employees_Select ストアド プロシージャの更新された列の一覧を表示している (フルサイズの画像を表示するにはクリックします)

[完了] をクリックしてウィザードを終了します。 DataSet デザイナーに戻ると、EmployeesDataTableManagerFirstNameManagerLastName の 2 つの列が追加されています。

EmployeesDataTable に 2 つの新しい列が含まれている

図 11: EmployeesDataTable に 2 つの新しい列が含まれている (フルサイズの画像を表示するにはクリックします)

更新された Employees_Select ストアド プロシージャが有効であり、TableAdapter の挿入、更新、削除の機能がまだ機能していることを示すために、ユーザーが従業員を表示および削除できる Web ページを作成しましょう。 ただし、このようなページを作成する前に、NorthwindWithSprocs DataSet の従業員を操作するための新しいクラスをビジネス ロジック レイヤーに最初に作成する必要があります。 手順 4 では、EmployeesBLLWithSprocs クラスを作成します。 手順 5 では、ASP.NET ページからこのクラスを使用します。

手順 4: ビジネス ロジック レイヤーを実装する

EmployeesBLLWithSprocs.vb という名前の新しいクラス ファイルを ~/App_Code/BLL フォルダーに作成します。 このクラスは、既存の EmployeesBLL クラスのセマンティクスを模倣します。ただし、この新しいクラスが提供するメソッドは少なく、(Northwind DataSet ではなく) NorthwindWithSprocs DataSet を使用します。 EmployeesBLLWithSprocs クラスに次のコードを追加します。

Imports NorthwindWithSprocsTableAdapters
<System.ComponentModel.DataObject()> _
Public Class EmployeesBLLWithSprocs
    Private _employeesAdapter As EmployeesTableAdapter = Nothing
    Protected ReadOnly Property Adapter() As EmployeesTableAdapter
        Get
            If _employeesAdapter Is Nothing Then
                _employeesAdapter = New EmployeesTableAdapter()
            End If
            Return _employeesAdapter
        End Get
    End Property
    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Select, True)> _
    Public Function GetEmployees() As NorthwindWithSprocs.EmployeesDataTable
        Return Adapter.GetEmployees()
    End Function
    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Delete, True)> _
    Public Function DeleteEmployee(ByVal employeeID As Integer) As Boolean
        Dim rowsAffected = Adapter.Delete(employeeID)
        'Return true if precisely one row was deleted, otherwise false
        Return rowsAffected = 1
    End Function
End Class

EmployeesBLLWithSprocsクラスの Adapter プロパティは、NorthwindWithSprocs DataSet の EmployeesTableAdapter のインスタンスを返します。 これは、クラスの GetEmployees および DeleteEmployee メソッドによって使用されます。 GetEmployees メソッドは、EmployeesTableAdapter の対応する GetEmployees メソッドを呼び出し、これが Employees_Select ストアド プロシージャを呼び出して結果を EmployeeDataTable に設定します。 DeleteEmployee メソッドは同様に、EmployeesTableAdapterDelete メソッドを呼び出し、これが Employees_Delete ストアド プロシージャを呼び出します。

手順 5: プレゼンテーション層でデータを操作する

EmployeesBLLWithSprocs クラスが完成したら、ASP.NET ページを通じて従業員データを操作する準備ができました。 AdvancedDAL フォルダー内の JOINs.aspx ページを開き、ツールボックスからデザイナーに GridView をドラッグして、その ID プロパティを Employees に設定します。 次に、GridView のスマート タグから、EmployeesDataSource という名前の新しい ObjectDataSource コントロールにグリッドをバインドします。

EmployeesBLLWithSprocs クラスを使用するように ObjectDataSource を構成し、SELECT タブと DELETE タブで、ドロップダウン リストから GetEmployees メソッドと DeleteEmployee メソッドが選択されていることを確認します。 [完了] をクリックして ObjectDataSource の構成を完了します。

EmployeesBLLWithSprocs クラスを使用するように ObjectDataSource を構成する

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

ObjectDataSource で GetEmployees メソッドと DeleteEmployee メソッドを使用する

図 13: GetEmployees および DeleteEmployee メソッドを使用するように ObjectDataSource を設定する (クリックするとフルサイズの画像が表示されます)

Visual Studio により、EmployeesDataTable の各列の GridView に BoundField が追加されます。 TitleLastNameFirstNameManagerFirstNameManagerLastName を除くすべての BoundFields を削除し、最後の 4 つの BoundFields の HeaderText プロパティの名前をそれぞれ Last Name、First Name、Manager's First Name、Manager's Last Name に変更します。

ユーザーがこのページから従業員を削除できるようにするために、2 つのことが必要です。 まず、スマート タグで [削除を有効にする] オプションをオンにすることで、GridView に対して削除機能を提供するように指示します。 次に、ObjectDataSource の OldValuesParameterFormatString プロパティを、ObjectDataSource ウィザードによって設定された値 (original_{0}) から既定値 ({0}) に変更します。 これらの変更を行った後、GridView と ObjectDataSource の宣言型マークアップは次のようになります。

<asp:GridView ID="Employees" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="EmployeeID" DataSourceID="EmployeesDataSource">
    <Columns>
        <asp:CommandField ShowDeleteButton="True" />
        <asp:BoundField DataField="Title" 
            HeaderText="Title" 
            SortExpression="Title" />
        <asp:BoundField DataField="LastName" 
            HeaderText="Last Name" 
            SortExpression="LastName" />
        <asp:BoundField DataField="FirstName" 
            HeaderText="First Name" 
            SortExpression="FirstName" />
        <asp:BoundField DataField="ManagerFirstName" 
            HeaderText="Manager's First Name" 
            SortExpression="ManagerFirstName" />
        <asp:BoundField DataField="ManagerLastName" 
            HeaderText="Manager's Last Name" 
            SortExpression="ManagerLastName" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="EmployeesDataSource" runat="server" 
    DeleteMethod="DeleteEmployee" OldValuesParameterFormatString="{0}" 
    SelectMethod="GetEmployees" TypeName="EmployeesBLLWithSprocs">
    <DeleteParameters>
        <asp:Parameter Name="employeeID" Type="Int32" />
    </DeleteParameters>
</asp:ObjectDataSource>

ブラウザーからページにアクセスして、ページをテストします。 図 14 に示すように、ページには各従業員とその上司の名前が一覧表示されます (上司がいる場合)。

Employees_Select ストアド プロシージャ内の JOIN によってマネージャーの名前が返される

図 14: Employees_Select ストアド プロシージャ内の JOIN が上司の名前を返す (フルサイズの画像を表示するにはクリックします)

[削除] ボタンをクリックすると、削除ワークフローが開始され、Employees_Delete ストアド プロシージャの実行で最高点に達します。 ただし、ストアド プロシージャで試行された DELETE ステートメントは、外部キー制約違反のために失敗します (図 15 を参照)。 具体的には、各従業員が Orders テーブルに 1 つ以上のレコードを持っているため、削除が失敗します。

従業員を削除するときに、その従業員に対応する注文がある場合は外部キー制約違反が発生する

図 15: 対応する注文を持つ従業員を削除すると、外部キー制約違反が発生する (フルサイズの画像を表示するにはクリックします)

従業員の削除を許可するために、以下を行うことができます。

  • 外部キー制約を連鎖削除に更新する。
  • 削除する従業員のレコードを Orders テーブルから手動で削除する。または
  • Employees レコードを削除する前に、Orders テーブルから関連レコードを最初に削除するように Employees_Delete ストアド プロシージャを更新する。 この手法については、「型指定された DataSet の TableAdapters に既存のストアド プロシージャを使用する」のチュートリアルで説明しました。

これは、読者のための演習として残しておきます。

まとめ

リレーショナル データベースを使用する場合、クエリで複数の関連テーブルからデータをプルすることは一般的です。 相関サブクエリと JOIN は、クエリで関連テーブルのデータにアクセスするための 2 つの異なる手法を提供します。 前のチュートリアルでは、TableAdapter が JOIN を含むクエリの INSERTUPDATE、および DELETE ステートメントを自動生成できないため、相関サブクエリを最も一般的に使用しました。 これらの値は手動で指定できますが、アドホック SQL ステートメントを使用する場合、TableAdapter 構成ウィザードが完了すると、カスタマイズが上書きされます。

幸いなことに、ストアド プロシージャを使用して作成された TableAdapter は、アドホック SQL ステートメントを使用して作成されたものと同じ問題は受けません。 そのため、ストアド プロシージャを使用するときに メイン クエリで JOIN を使用する TableAdapter を作成できます。 このチュートリアルでは、このような TableAdapter を作成する方法について説明しました。 まず、TableAdapter の メイン クエリに対して JOIN なしの SELECT クエリを使用して、対応する挿入、更新、および削除のストアド プロシージャが自動的に作成されるようにしました。 TableAdapter の初期構成が完了した後、JOIN を使用するように SelectCommand ストアド プロシージャを拡張し、TableAdapter 構成ウィザードを再実行して EmployeesDataTable の列を更新しました。

TableAdapter 構成ウィザードを再実行することで、Employees_Select ストアド プロシージャによって返されるデータ フィールドを反映するように EmployeesDataTable の列が自動的に更新されました。 または、これらの列を DataTable に手動で追加することもできました。 DataTable に列を手動で追加する方法については、次のチュートリアルで説明します。

プログラミングに満足!

著者について

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

特別な感謝

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