次の方法で共有


.NET での n 層アプリケーションの作成

Microsoft .NET へのアップグレード

Paul D. Sheriff
PDSA, Inc.

February 2002
日本語版最終更新日 2002 年 9 月 19 日

要約: n 層アプリケーションの各種のタイプについて説明した後に、Web サービスからデータを返し、Windows アプリケーションから Web サービスを利用できる型指定されたデータセットを作成する方法を説明します。

目標

  • n 層アプリケーションのタイプを確認する。
  • 優れた n 層アプリケーションの目標を確認する。
  • Web サービスからデータを返すことができる型指定されたデータセットの作成方法を学ぶ。
  • Windows アプリケーションから Web サービスを利用する。

前提条件

  • n 層アプリケーションの開発経験があること。
  • クラスについての知識があること。
  • OleDbDataAdapter と DataSet を使用した経験があること。
  • 型指定されたデータセットの作成方法を知っていること。
  • Microsoft® Visual Studio® .NET でフォームを作成できること。
  • リレーショナル データベースと Microsoft ADO.NET に関する知識があること。
  • Microsoft® .NET で Web サービスを作成した経験があること。

目次

n 層アプリケーションのタイプ n 層アプリケーションの作成 Visual Basic 6.0 との違い 要約

n 層アプリケーションのタイプ

これまでにプログラマたちはさまざまなタイプの n 層アプリケーションを開発してきました。Microsoft Visual Basic® 4.0 に初めてクラスが導入されて以来、多くのプログラマは n 層アプリケーションの作成方法の決定版を作り出そうと試みてきました。彼らはいずれも頭脳明晰な人々でしたが、n 層アプリケーションの作成方法に関するコンセンサスが得られたことは一度もありませんでした。n 層アプリケーションの開発手法は、この世のプログラマの数だけ存在するように見えます。以下に、考えうる方法の例をいくつか示します。

  • 送信されてきたすべての SQL ステートメントに対し、非接続型の ADO レコードセットを返す 1 つのクラスを含んだコンポーネントを作成します。すべての更新は ADO レコードセットの中で実行され、バッチ更新のためにコンポーネントに返送されます。
  • 各種のビジネス プロセスをベースにした複数のクラスを含んでいるコンポーネントを作成します。ビジネス プロセスのためのすべてのデータは、このコンポーネントに渡されます。コンポーネントは、与えられたデータをもとに、適切なテーブルを更新します。ビジネス プロセスのユーザー インターフェイスをサポートするために必要なデータ ビューは、別のコンポーネントが返します。
  • テーブル 1 つにつき 1 つのクラスを作成し、クラスに ADO を埋め込みます。これは、EXE と (DLL 内の) クラスの両方がクライアント マシンにインストールされる論理的な n 層モデルです。
  • テーブル 1 つにつき 1 つのクラスを作成し、クライアント サイドで ADO を使用します。このクライアント サイド クラスは、MTS 上で実行されているサーバー サイドのデータ クラスに、DCOM を通して SQL を渡します。サーバー サイドのデータ クラスは、クライアント サイドに非接続型の ADO レコードセットを返します。
  • テーブル 1 つにつき 2 つのクラスを作成し、そのうちの 1 つはクライアント サイドの EXE からプロパティを設定できるようにします。これらのプロパティは XML 文字列へとまとめられ、DCOM を通して、MTS 上で実行されているサーバー サイド クラスに渡されます。XML はデータの取得または変更の方法に関する情報と、クライアント サイド クラスに返される非接続型の ADO レコードセットを含んでいます。
  • テーブル 1 つにつき 1 つのクラスを、クライアント サイドで DOMDocument オブジェクトを使用して作成し、すべてのデータをこれで処理します。クライアント サイド クラスは、すべてのプロパティを XML 文字列にまとめ、サーバー サイドのデータ クラスに送信します。サーバー サイドは XML から命令 (SQL) を抽出し、データベース サーバーに対して適切なアクションを実行します。その後、サーバー サイド クラスは XML をクライアント サイド クラスに返して、クライアントに対し、データベースで何が起こったかを通知します。このシナリオでは、すべてのテーブルに対して 1 つのデータ クラスしか存在しません。
  • すべてのテーブルに対して 1 つのサーバー サイド クラスを作成します。クライアント サイドはサーバー サイド クラスに SQL を渡し、非接続型の ADO レコードセットを受け取ります。すべてのフォームは、データの処理にこれらの ADO レコードセットを使用します。
  • Web サーバーに対して XML データを求める SOAP 要求を送信するクライアント サイド EXE を作成します。XML は、クライアント サイドでは DOMDocument オブジェクトを使って処理されます。

このように、n 層アプリケーションの作成方法にはさまざまなものがあります。これらはいずれも正常に動作し、それぞれの長所と短所を持っています。このドキュメントの目標は、これらの方法に反論を加えたり、それぞれの長所と短所を述べることではなく、単に Visual Basic .NET で n 層データ クラスを作成する方法を示すことです。

このドキュメントでは、Visual Studio .NET の組み込みツールを使って、型指定されたデータセットを作成する方法を学びます。型指定されたデータセットは.NET の DataSet クラスを継承します。また、このクラスは基本テーブルの個々の列に対応するプロパティを提供します。DataSet へのデータ ソースからのデータの格納には、標準のデータ アダプタ オブジェクトを使用します。この型指定されたデータセットを生成するウィザードは、データ ソースからスキーマ情報を読み込み、これらのデータ型をそれぞれの列にマッピングします。これが型指定されたデータセットと呼ばれるのはこのためです。

型指定されたデータセットを使用すると、いくつかの方法で開発プロセスを短縮することができます。第 1 に、この DataSet クラスからオブジェクトを作成すると、Microsoft® IntelliSense® が列の名前のリストを表示してくれるようになるので、プログラマは列の名前を覚えておく必要がなくなります。列の名前はコンパイル時にチェックされるため、ランタイム エラーはなくなります。第 2 に、フロントエンド クライアント アプリケーションで SQL を使う必要がなくなります。すべての SQL はデータ アダプタに埋め込まれています。これらの型指定されたデータセットを独立したコンポーネントに格納することで、これらのクラスを複数のプロジェクトで再利用することができます。

優れた n 層アプリケーションの目標

n 層デザインが登場した理由は、クライアント サーバー モデルの失敗にあります。n 層アプリケーション デザインが達成するべき目標にはさまざまなものがあります。以下に、そのいくつかの例を示します。

  • 下位のデータ アクセス方式を変更した場合でも、クライアント サイド コードは変更しなくて済むようになっていなくてはなりません。
  • すべてのデータ アクセス ルーチンは、関数呼び出しではなくオブジェクトとして公開されなくてはなりません。たとえば、ADO は ODBC API 呼び出しよりも使うのがはるかに簡単です。
  • クライアント サイド コードから SQL をなくさなくてはなりません。クライアント コードは、メソッドとプロパティのみを扱うようになっている必要があります。
  • クライアント サイド コードからテーブル名と列名をなくさなくてはなりません。型指定されたデータセットは、テーブル名と列名をプロパティとして提示することができるため、プログラマは文字列の名前を入力する代わりに、IntelliSense リストを使用することができます。これは、コンパイル時にデータ型と列の名前のチェックを行えるということも意味します。
  • クライアント コードは、データの出所を気にせずに済むようになっていなくてはなりません。クライアント コードはオブジェクトの形でデータを取得し、これを変更するだけでよく、具体的な細部はオブジェクトが処理します。
  • クライアント サイドで必要となるコーディングは単純化されなくてはなりません。アプリケーションは、多数の関数を使用するのではなく、プロパティとメソッドを持ったオブジェクトを使用することになります。
  • クラスの作成と使用は、関数呼び出しよりも簡単です。
  • クライアント サイド コードを壊すことなく、アプリケーションに新たな機能を追加したり、既存の機能を変更したりすることが簡単になります。

n 層の短所

優れた n 層アプリケーションにはさまざまな長所がありますが、いくつかの短所もあります。

  • 多数のクラスを作成することになります。これは保守上の問題を引き起こす可能性があり、実行時に新しいクラスを作成するのに要する時間のせいで、パフォーマンス上の問題が生じることもあります。
  • n 層は、データの取得元のテーブルの構造がわからない場合には、うまく機能しません。たとえば、ユーザーが複数のテーブルから複数の列を取得する Query By Example (QBE) アプリケーションでは、そのためのクラスを実行時に生成することはできません。
  • レポートの作成は n 層デザインには適していません。レポート ライターは、データの取得にクラスを使用しません。

結局のところ、優れた n 層デザインの長所は、その短所をはるかに上回っていると言えます。どうしても n 層を使用できないケースでは、典型的なクライアント サーバー開発手法を使用してください。必要ならば、同じアプリケーションで両方のパラダイムを混在させても何も問題はありません。

n 層アプリケーションの作成

真の分散型 n 層アプリケーションでは、それぞれの層のコンポーネントが、別々のコンポーネントに、さらには別々のマシンに分割されます。図 1 は、個々のマシンに複数のコンポーネントを持つ n 層アプリケーションの典型的な例を示しています。

図 1. 3 つの物理層を持ち、各マシン上に 1 つまたは複数の論理層を持つ分散型の n 層アプリケーション

n 層アプリケーションの構成方法にはさまざまなものが考えられます。たとえば、ビジネス ルールを別のマシンに分割する必要がある場合には、図 2 に示すように、クライアント アプリケーションとビジネス ルール層の間の通信に .NET リモーティングを使用することができます。

図 2. 保守を容易にするために、ビジネス ルールを別のマシンに置くことができる

また、クライアント上にデータ入力検証ルール コンポーネントを置いて、必須のフィールドやフォーマッティングなどの単純なルールのチェックを行うことができます。これらは、単にチェックするためだけにネットワークとの通信を行うのが望ましくないルールです。さらに、データ層コンポーネントと同じ層にビジネス ルール層を追加して、テーブル間でデータを比較する複雑なビジネス ルールのチェックを行うこともできます。

これらは、利用可能な構成のごく一部の例に過ぎません。もちろん、個々の状況に応じたユニークな構成を考え出すこともできるでしょう。コンポーネントの物理的な実装の構造がどうであろうと、プログラムの論理構造は上の図に示したように、コンポーネント単位に分割するようにしてください。

ユーザー インターフェイスの作成

図 1 の例では、クライアント層は Windows アプリケーションとビジネス ルール コンポーネントから構成されています。Windows アプリケーションは、データに対するすべての要求と更新を、ビジネス ルール コンポーネントを通して実行します。これにより、データの格納場所が Windows アプリケーションから隔離されます。この方法の利点は、データの取得場所を変更した場合でも、ビジネス ルール コンポーネントに変更を加えるだけでよく、クライアント アプリケーションには変更を加えずに済むことです。

図 3. この DataGrid は、ビジネス ルール コンポーネントから返される結果に連結されている

次の操作を行って、Windows フォーム上の DataGrid コントロールに従業員情報を表示する単純な Windows クライアント アプリケーションを作成します。

  1. EmpClient という名前の新しい Windows アプリケーション プロジェクトを作成します。
  2. 既定のフォーム (Form1.vb) のファイル名を frmEmpInfo.vb に変更します。
  3. フォームの Name プロパティを EmpInfo に設定します。
  4. フォームの Text プロパティを Employee Information に設定します。
  5. プロジェクトのプロパティのスタートアップ オブジェクトを EmpInfo に設定します。
  6. このフォームに DataGrid をドラッグします。Name プロパティを grdEmps に設定します。
  7. このフォームに Button コントロールを追加します。Name プロパティを btnUpdate に設定します。Text プロパティを Update に設定します。

これで従業員フォームのユーザー インターフェイスは完成です。次は、この DataGrid に格納するデータを取得するためのコンポーネントの作成に着手します。

データ層の作成

データ層は、データ ソースに接続し、型指定されたデータセットを作成し、コンポーネントの中のメソッドからこのデータセットを返す仕事を行います。

次の操作を行って、データ層コンポーネントを作成します。

  1. [ソリューション エクスプローラ] ウィンドウで、EmpClient という名前のソリューションを右クリックします。
  2. ショートカット メニューの [追加] をクリックし、[新しいプロジェクト] をクリックします。
  3. [クラス ライブラリ] テンプレートを選択します。このクラス ライブラリの名前を EmpData に設定します。
  4. プロジェクトから Class1.vb という名前のクラス ファイルを削除します。
  5. プロジェクトに新しいコンポーネントを追加するために、[プロジェクト] メニューの [コンポーネントの追加] をクリックします。コンポーネントの名前を clsEmp.vb に設定します。
  6. このコンポーネントのコードを表示し、クラスの名前を clsEmp から Employees に変更します。
  7. デザイン ビューで、ツールボックスの [データ] タブの SqlDataAdapter コントロールをクリックし、このコンポーネントのデザイン サーフェスにドラッグします。
  8. ウィザードの各ステップを実行して、SQL Server に接続し、サーバー上の Northwind データベースを指定します。このデータベースの Employee テーブルのすべての行と列を選択します。
  9. SqlConnection オブジェクトの名前を SqlConnection1 から cnNorthwind に変更します。SqlDataAdapter オブジェクトの名前を SqlDataAdapter1 から daEmps に変更します。
  10. daEmps オブジェクトをクリックし、[データ] メニューの [データセットの生成] をクリックします。新しいデータセットの名前を dsEmps に設定します。

これで、データ アクセス オブジェクトを含んだコンポーネントが作成できました。通常のクラスの代わりにコンポーネントを使用しているのは、Connection および DataAdapter オブジェクトをデザイン サーフェスにドラッグする機能が必要だからです。これはコンポーネントでは可能ですが、通常のクラスではできません。もちろん、データ アダプタと接続オブジェクトを、コードを使って独自に作成することも可能ですが、こちらの方法ははるかに簡単です。

このコンポーネントを追加したら、後はコンポーネントに 2 つのメソッドを追加するだけです。第 1 のメソッド GetData は、従業員データが格納された、型指定されたデータセットへの参照を返します。第 2 のメソッド Update は、型指定されたデータセットをパラメータとして受け取り、このデータセットの変更点をバックエンド データ ソースにサブミットします。

データ コンポーネントの中の GetData メソッド

このメソッドは、dsEmps 型のオブジェクトを宣言します。これは、さきほど生成した型指定されたデータセットの名前です。このファイルは、[ソリューション エクスプローラ] ウィンドウでは dsEmps.xsd として表示されています。これは Northwind データベースの Employees テーブルのスキーマ定義ファイルです。この xsd ファイルの背後にあるコードは、dsEmps という名前の型指定されたデータセットです。

                  
Public Function GetData() As dsEmps
    Dim dsData As dsEmps

    Try
        dsData = New dsEmps()

        daEmps.Fill(dsData)

        Return dsData
    Catch
        Throw
    End Try
End Function

dsEmps オブジェクトのインスタンスを作成したら、SqlDataAdapter オブジェクトを使用して、dsEmps オブジェクトに Employees テーブルからのデータを格納します。その後、メソッドはこの型指定されたデータセットを他のコンポーネントに返します。このデータセットの利用方法は、次のセクションで説明します。

データ コンポーネントの中の Update メソッド

Update メソッドは、呼び出し元のプログラムから型指定されたデータセットを受け取り、SqlDataAdapter オブジェクトの Update メソッドを実行して、データセット内の変更点を Employees テーブルに送信します。また、この同じデータセットを呼び出し元のプログラムに返して、TimeStamps フィールドや Identity フィールドなどの更新されたフィールドを、呼び出し元プログラムのデータセットにマージできるようにします。

                  
Public Function Update(ByVal dsData As dsEmps) As dsEmps
    Try
        ' テーブル内のデータを更新する
        daEmps.Update(dsData)

    Catch
        ' 例外はクライアントに対してスローする
        Throw

    End Try

    Return dsData
End Function

この 2 つのメソッドでの構造化例外処理の使い方に注目してください。何らかのエラーが発生すると、例外は単に呼び出し元のコンポーネントに対してスローされます。これらのコンポーネントの中で、例外の処理は行われません。

Web サービスの作成

図 1 では、データ層が Web サービスから呼び出されています。次は、上で作成した EmpData コンポーネントを呼び出す Web サービス プロジェクトを作成します。

  1. [ソリューション エクスプローラ] ウィンドウで、EmpClient という名前のソリューションを右クリックします。
  2. ショートカット メニューの [追加] をクリックし、[新しいプロジェクト] をクリックします。
  3. [ASP.NET Web サービス] テンプレートを選択し、このプロジェクトの名前を EmpWS に設定します。
  4. プロジェクトから Service1.asmx ファイルを削除します。
  5. 新しい Web サービス ファイルを追加するために、[プロジェクト] メニューの [Web サービスの追加] をクリックします。この新しい Web サービスの名前を Employees.asmx に設定します。
  6. EmpWS プロジェクトをクリックし、EmpData プロジェクトへの参照を追加します。

これで Employees という名前の Web サービスが作成されました。次に、データ コンポーネントからのデータセットを使用する 2 つのメソッドを作成します。一貫性を持たせるために、この 2 つのメソッドにはデータ コンポーネントのメソッドと同じ名前を付けます。

Web サービスの中の GetData メソッド

Web サービスの中の GetData メソッドは、EmpData.Employees クラスへの参照を作成します。この新しいオブジェクトを作成したら、このオブジェクトの GetData メソッドを呼び出して、この Web メソッドからデータセットを返します。

                  
<WebMethod()> Public Function GetData() _
 As EmpData.dsEmps
    Dim dc As EmpData.Employees

    Try
        dc = New EmpData.Employees()

        Return dc.GetData

    Catch
        ' 例外はクライアントに対してスローする
        Throw

    End Try
End Function

図 1 では、ビジネス ルール コンポーネントはこの Web サービスからデータを取得していました。単に Web サービス プロジェクトの中で型指定されたデータセットを作成しない理由は、真の分散型アプリケーションを作成しない場合に、データ コンポーネントを Windows アプリケーションから直接に利用できる柔軟性を確保するためです。Web サービス プロジェクトを削除し、ビジネス ルール層を Web サービスではなくデータ コンポーネントと直接に通信を行うように変更すれば、他のコードは一切変更する必要がありません。

Update メソッド

この Web サービス プロジェクトの中の Update メソッドは、引数として渡されたデータセットを、単にデータ コンポーネントの Update メソッドの引数として直接渡します。

                  
<WebMethod()> Public Function Update( _
 ByVal dsData As EmpData.dsEmps) As EmpData.dsEmps
    Dim dc As EmpData.Employees

    Try
        dc = New EmpData.Employees()

        dc.Update(dsData)

    Catch
        ' 例外はクライアントに対してスローする
        Throw

    End Try

    Return dsData
End Function

ビジネス ルール コンポーネントの作成

次は、ビジネス ルール コンポーネントを Windows アプリケーションに接続し、ビジネス ルール コンポーネントからデータを取得するために Web サービスを呼び出すことによって、これまでのすべてのプロジェクトを統合します。

次の操作を行って、Windows アプリケーションとデータ層の間のインターフェイスの役割を果たすコンポーネントを作成します。

  1. [ソリューション エクスプローラ] ウィンドウで、EmpClient ソリューションを右クリックし、ショートカット メニューの [追加] - [新しいプロジェクト] をクリックします。

  2. [クラス ライブラリ] テンプレートを選択し、この新しいプロジェクトの名前を EmpBusRule に設定します。

  3. Class1.vb ファイルの名前を clsEmployee.vb に変更します。

  4. Public Class の名前を Class1 から Employees に変更します。

  5. ソリューションが正常にコンパイルされることを確認し、また参照に必要な Web サービス ファイルをビルドするために、[ビルド] メニューの [ソリューションのビルド] をクリックします。

  6. EmpBusRule プロジェクトをクリックし、EmpWS.vsdisco ファイルへの Web 参照を追加します。

       

    vsdisco ファイルへの参照を設定できない場合には、代わりに Employees.asmx ファイルへの参照を設定します。

  7. このプロジェクトの [Web 参照] フォルダを展開し、LocalHost 項目 (またはその他の Web サーバーの名前) を EmpService に変更します。

ビジネス ルール コンポーネントの中の GetData メソッド

ビジネス ルール コンポーネントの中の GetData メソッドは、単に Web サービス コンポーネントにアクセスし、データ層に対してデータを要求します。これはデータを取得するためのアプローチとしては間接的に過ぎるように見えるかもしれませんが、これによって n 層アプリケーションを真の分散型にすることができます。

                  
Public Function GetData() As EmpService.dsEmps
    Dim ws As EmpService.Employees

    Try
        ws = New EmpService.Employees()

        Return ws.GetData

    Catch
        Throw

    End Try
End Function

ビジネス ルール コンポーネントの中の Update メソッド

Update メソッドは、変更点のデータセットを受け取り、ビジネス ルールの違反がないことをチェックして、HTTP インターフェイスを通して Web サービス コンポーネントにデータを返す仕事を行います。

                  
Public Function Update( _
 ByVal dsData As EmpService.dsEmps) As EmpService.dsEmps
    Dim ws As EmpService.Employees

    Try
        ws = New EmpService.Employees()

        ' ビジネス ルールをチェックする
        Me.Check(dsData)

        ' テーブル内のデータを更新する
        ws.Update(dsData)

    Catch
        ' 例外はクライアントに対してスローする
        Throw

    End Try

    Return dsData
End Function

ビジネス ルール コンポーネントの中の Check メソッド

Check メソッドは、データセットの行の挿入または更新を行う前にチェックしなくてはならないビジネス ルールを格納する場所です。

                  
Public Sub Check(ByVal dsData As EmpService.dsEmps)
    Dim strMsg As String
    Dim row As EmpService.dsEmps.EmployeesRow

    ' ビジネス ルールをチェックする
    For Each row In dsData.Employees.Rows
        If row.RowState = DataRowState.Added Or _
         row.RowState = DataRowState.Modified Then
            If row.FirstName.Trim() = "" Then
              strMsg &= "First Name must be filled in" & _
               ControlChars.CrLf
            End If
            If row.LastName.Trim() = "" Then
              strMsg &= "Last Name must be filled in" & _
               ControlChars.CrLf
            End If
            If row.HireDate < row.BirthDate Then
                strMsg &= "Hire Date must be greater 
                           than Birth Date" & _
                 ControlChars.CrLf
            End If
        End If
    Next

    If strMsg <> "" Then
        ' カスタム エラー メッセージを入れて
        ' 新しい ApplicationException をスローする
        Throw New ApplicationException(strMsg)
    End If
End Sub

RowState プロパティをチェックして、行の追加または更新が行われたかどうかを確認しなくてはならないことに注意してください。行が削除された場合には、チェックを行う必要はありません。Check メソッドでは、型指定されたデータセットを使用することの利点がわかります。データセットの中のインデックスを通して列名を参照する代わりに、実際のプロパティ名を使用することができます。これによりタイプ セーフティが実現されますし、IntelliSense リストに列名が表示されるため、データベースで列名を調べる必要がありません。

Windows アプリケーションからのデータの使用

すべてのコンポーネントを統合できたので、次は Windows アプリケーションでビジネス ルール コンポーネントからのデータを使用します。次の操作を行います。

  1. [ソリューション エクスプローラ] ウィンドウで、EmpClient プロジェクトをクリックします。

  2. EmpBusRule プロジェクトへの参照を追加します。

  3. フォームのコードを表示し、次のコードに示すように Private mdsEmps 変数を追加します。

    Public Class EmpInfo
        Inherits System.Windows.Forms.Form
    
        Private mdsEmps As EmpBusRule.EmpService.dsEmps
    

フォーム上のこのメンバ変数は、Northwind データベースの中の Employees テーブルを表す型指定されたデータセットです。この変数を使って、従業員フォーム上の DataGrid コントロールにデータを格納します。

DataGrid へのデータのロード

次に、DataGrid にデータをロードするためのルーチンを作成する必要があります。まず、フォームの Load イベント プロシージャにコードを追加します。

  1. フォームをダブルクリックして、Load イベント プロシージャを表示します。

  2. 次のコードを追加します。

    Private Sub EmpInfo_Load( _
     ByVal sender As System.Object, _
     ByVal e As System.EventArgs) Handles MyBase.Load
        GridLoad()
    End Sub
    
  3. Load イベント プロシージャの直後に、GridLoad プロシージャを作成します。

    Public Sub GridLoad()
        Dim br As EmpBusRule.Employees
    
        Try
            br = New EmpBusRule.Employees()
    
            ' mdsEmps はこのフォーム上の型指定されたデータセットである。
            mdsEmps = br.GetData
    
            grdEmps.DataMember = "Employees"
            grdEmps.DataSource = mdsEmps
    
        Catch exp As Exception
            MsgBox(exp.Message)
    
        End Try
    End Sub
    

GridLoad プロシージャは新しいビジネス ルール オブジェクトを宣言します。その後、ビジネス ルール オブジェクトの中の GetData メソッドを使用して、新しい型指定されたデータセット mdsEmps を代入します。DataGrid コントロールの DataMember にはテーブル名を、DataSource プロパティにはデータセット オブジェクトを代入します。

これでアプリケーションを実行する準備ができました。間違いがなければ、DataGrid に従業員データがロードされるはずです。

  1. EmpClient プロジェクトをスタートアップ プロジェクトとして設定します (まだ設定されていない場合)。
  2. [F5] キーを押して、アプリケーションを実行します。

図 2 のように、リスト ボックスに従業員データが表示されるはずです。

DataGrid からのデータの更新

次に、フォーム上の [Update] ボタンの背後に、グリッド内のデータに加えた変更をデータ層に返送するプロシージャを作成します。もちろん、DataSet への変更はまずビジネス ルール コンポーネントに送られ、そこから Web サービス コンポーネントへ、最後にデータ層コンポーネントへと送られます。データ層コンポーネントは SQL Server に接続し、変更点をサーバーに送信します。

                  Private Sub btnUpdate_Click( _
 ByVal sender As System.Object, _
 ByVal e As System.EventArgs) Handles btnUpdate.Click
    Dim br As New EmpBusRule.Employees()
    Dim dsChanges As New EmpBusRule.EmpService.dsEmps()
    Dim strMsg As String

    Try
        If mdsEmps.HasChanges Then
            dsChanges.Merge(mdsEmps.GetChanges())

            MsgBox("Count = " & _
             CStr(dsChanges.Employees.Rows.Count))

            ' サーバー上のデータを更新する
            dsChanges = br.Update(dsChanges)

            MsgBox("Data Has Been Updated Successfully")

            ' 変更点を受け取ってマージするか、
            ' テーブルからデータを再ロードするかのどちらかの
            ' 方法が選べる。
            ' 筆者は、他のユーザーが加えた変更も反映させられることから、
            ' 再ロードの方を好んでいる。
            'mdsEmps.Merge(dsChanges)
            'mdsEmps.AcceptChanges()

            ' 問題がなければ、Web サービスから
            ' すべてのデータを更新する
            GridLoad()
        Else
            MsgBox("No changes have been made 
                    to the data")
        End If

    Catch exp As ApplicationException
        MsgBox(exp.Message)

    Catch exp As Exception
        MsgBox(exp.Message)

    End Try
End Sub

このイベント プロシージャの最初の部分は、DataSet に何らかの変更が加えられたかどうかをチェックします。変更が加えられていた場合には、DataSet クラスの GetChanges メソッドを使用して、変更されたデータ行を取得します。これにより、DataGrid で変更された行だけが返されます。

データセットからの少数の行のリストが得られたら、これをビジネス ルール コンポーネントの Update メソッドにサブミットします。ビジネス ルール コンポーネントはこれを Web サービス コンポーネントに送り、Web サービス コンポーネントはこれをデータ層コンポーネントに送って、最後には SQL Server が更新されます。データセット内の行に何らかの変更が加えられた場合には (TimeStamp フィールドの更新やアイデンティティ フィールドの更新など)、それらの行がこのプロシージャに返されます。このデータをメインのデータセットにマージすることもできますし、データベースから (もちろん一連のコンポーネントを通して) データセット全体を再ロードすることもできます。

バックエンドにサブミットしようとしている変更点には、ビジネス ルールに対する違反が含まれている可能性があります。たとえば、誰かが従業員のファースト ネームを削除した場合、データ行の中のファースト ネームの存在をチェックするビジネス ルールは失敗します。これは ApplicationException オブジェクトとしてスローされます。このタイプの例外は先にチェックし、返されたエラー メッセージを表示するようにします。このメッセージは、違反があったビジネス ルールの説明文です。

最後にチェックしなくてはならないのは、総称的な例外です。たとえば、データベース サーバーが停止していて、通常の例外がスローされることがあります。また、更新した行を、直前に別のユーザーが更新していたために、並列性の例外がスローされることもあります。

Visual Basic 6.0 との違い

n 層アプリケーションのデザインの概念はこれまでとほとんど同じですが、その実装は大きく異なっています。Web サービスと ADO.NET のおかげで、プログラマが書かなくてはならないコードの量は大幅に減っています。

要約

このドキュメントでは、n 層アプリケーションを構築する方法について説明しました。ここでは 1 つの方法しか示しませんでしたが、ここで使用している形式は非常に単純で、簡単に作成することができます。作成したコンポーネントは 1 台のマシンに置くこともできますが、コンポーネントを別のマシンに移動して、.NET リモーティングと Web サービスを使ってソリューションのスケーリングを行うことも可能です。アプリケーションの論理的実装と物理的実装のどちらを扱う場合でも、アプリケーションの開発にあたっては、つねに個々のプロセスに独立したコンポーネントを使用するようにするべきです。

執筆者について

Paul D. Sheriff は Southern California のカスタム ソフトウェア開発およびコンサルティング会社、PDSA, Inc.のオーナーです。Paul は Southern California の MSDN Regional Director で、『Paul Sheriff Teaches Visual Basic』というタイトルの Visual Basic 6.0 関連の書籍を書いており、Keystone Learning Systems のために Visual Basic、SQL Server、.NET、および Web 開発関連の 72 本以上のビデオを製作しています。近く、Ken Getz との共著の『ASP.NET Jumpstart』という名前の SAMS のための書籍が出版される予定です。詳細については、PDSA, Inc.の Web サイト (www.pdsa.com) を参照してください。

Informant Communications Group について

Informant Communications Group, Inc. (www.informant.com) は、情報テクノロジ セクタに焦点を当てた多角的なメディア会社です。1990 年に創設された ICG は、ソフトウェア開発関連の出版事業、カンファレンス、カタログの発行、および Web サイトを専門としています。米国と英国にオフィスを持つ ICG は、有名なメディアおよびマーケティング コンテンツ インテグレータとして、IT プロフェッショナルに対して高品質の技術情報を提供してきました。

Copyright c 2002 Informant Communications Group and Microsoft Corporation

テクニカル エディティング: PDSA, Inc.