Visual Studio .NETのウィザードを使ってN階層アプリケーションを作成する:パート1はじめにMicrosoftはRAD(Rapid Application Development)ツールのための優れたツールを開発者に提供することで知られています。MS Access、Visual Studio 6、Visual Interdevなどの環境で、コントロールやプロパティ、自動生成コードを視覚的に組み合わせることで、アプリケーションをすばやく開発できます。Visual Studio .NETはこれらのツールを統合し、数多くのプログラミング言語に対応している素晴らしい開発環境です。 Visual Studio .NET(以下、VS)には、アプリケーション開発に役立つウィザードが多数用意されています。しかし残念ながら、ウィザードでは効率的なプログラミング手法が使われない傾向にあります。具体的に言うと、コードが複数の層に分離されず、ビジネスロジックが分離されないのです。VSの既定のモデルでは、データオブジェクトをフォームにドラッグアンドドロップしながらフォームを作成します。コードは必要に応じて作成されますが、データアクセスコードとビジネスロジックコードが区別されず、ユーザーインターフェイスのフォームオブジェクト内に直接作成されます。このため、コードの再利用が難しく、同じテーブルデータを複数のフォームで使用する場面ではコードの重複が発生します。 今日のアーキテクチャでは、コードを複数の層に分離するN階層アプローチが推奨されています。N階層アプローチでは、少なくともデータアクセス層、ビジネスロジック層、プレゼンテーション層の3つに分離されます。アプリケーションの各種パーツを複数のサーバー上に置く分散アプリケーションの場合は、より多くの層が必要になることもあります。 層を分離する主なメリットは2つあります。1つはコードの再利用が容易になることで、もう1つはコードとデータベースの結合を回避できることです。データアクセス層とビジネスロジック層を分離すると、データのアクセスと使用に必要なコードをあちこちに繰り返し記述しなくても、さまざまなフォームを使ってデータを収集および表示できます。コードとデータベースの結合を回避すると、データベースのスキーマを変更する際にコードを修復する量が少なくなり、データストレージプロバイダを変更するときでも、コードを大幅に変更しないで済みます。 Microsoft .NETは、OOP(オブジェクト指向プログラミング)の標準を目指して、開発者のサポートと支援に力を入れてきました。OOPは高度で深遠な話題なので、ここでは詳しく説明しませんが、1つだけ、データベースアプリケーションの開発者にとって興味深い「ビジネスオブジェクト」について簡単に触れておくことにします。データベースのテーブルとフィールドがエンティティと属性の実装において重要な役割を果たすのに対し、ビジネスオブジェクトは特定のエンティティのプロパティと動作を併せて実装します。アプリケーションが各エンティティ(テーブル)を表すビジネスオブジェクトクラスのインスタンスを作成すると、そのプロパティを介して属性にアクセスし、メソッドを介してエンティティの動作を呼び出せるようになります。また、この手法を採用すると、エンティティに関するコードをすべて1つの場所にまとめておいて、アプリケーションのその他のパーツから簡単に参照することが可能です。さらに、ビジネスオブジェクトで継承やポリモーフィズムを利用すると、非常に柔軟で強力なプログラミングが可能になるため、わずかなコードで大量の処理を実行することができます。 パート1 - Visual Studio .NET 2003Visual Studio .NET 2003には、データベースアプリケーションを短時間で構築するためのウィザードやコード生成ツールが用意されていますが、本稿ではコードを複数のモジュールまたはクラスに分離して、アプリケーションの層を作成する方法について説明します。その例として、以降ではNorthwindデータベースを使用し、「Orders」テーブルや「Order Details」テーブルを表示および編集するためのフォームを作成します。 プロジェクトの作成最初にソリューションエクスプローラを使って新しいプロジェクトを作成します。この例ではWindowsフォームを作成しますが、Webフォームでもほとんど同じです。真の3層アプリケーションを作成する場合は、データアクセス層とビジネスロジック層のクラスオブジェクトを別々に作成しますが、モジュールは後で簡単に移動できます。 データオブジェクト層オブジェクト指向プログラミング(OOP)の原則に従って、まず取り扱う情報(通常はデータベースの情報)を含むデータオブジェクトを作成します。.NETでは、型指定されたデータセットを使うのが最も簡単です。このツールを使うと、通常のデータセットクラスがラップされ、オブジェクト指向に基づいたデータアクセスや、プロパティ(フィールド)の厳密な型指定が可能になります。コレクションや配列リストなどの構造でもデータベーステーブルオブジェクトを表現できますが、VSのほとんどのウィザードでは、型指定されたデータセットが使用されます。 新しいデータセットを作成するには、プロジェクトを右クリックして[Add]、[Add New Item]の順にクリックします。ウィザードの場合は、Datasetオブジェクトを選択して、新しいデータオブジェクトに「OrdersDO」などの適当な名前を指定します。ウィザードによって、XSDと型指定されたデータセットに必要なコードが生成され、デザインサーフェイスが表示されます。開発者はこのデザインサーフェイスを使ってテーブルをサーバーエクスプローラからデータセットのスキーマにドラッグして追加したり、あるいは他のウィザードを使用してリレーションシップや制約を追加したりできます。テーブルからフィールドをいくつか除外する場合は、スキーマから削除します。本稿の例では、「Orders」テーブルと「Order Details」テーブルを、サーバーエクスプローラからデザインサーフェイスにドラッグしました。出荷のデータは一切必要ないので、「Orders」テーブルでは4つのフィールドだけ残してすべて削除しました。ツールボックスの[XML Schema]のセクションでデータリレーションシップを選び、Ordersオブジェクトにドラッグアンドドロップします。リレーションシップウィザードでは「Order Details」を子テーブルに選んでください。ここまでの作業を終えると、図1のように表示されるはずです。 生成されるコード型指定されたデータセットの場合、データテーブルや行を抽象化するため、およびデータフィールド(プロパティ)の厳密な型指定を可能にするために、数百行のコードが生成されます。これにより、構文やIntelliSenseがデザイン時に検証され、オブジェクト指向的な方法でデータオブジェクトを参照できるようになります。生成されたコードを表示するには、プロジェクトを選択してソリューションエクスプローラの最上部にあるアイコンをクリックし、ファイルを表示します。次に、データセットの隣の[+]を展開してください。表示される2つのファイルのうち、拡張子が.vb(または.cs)であるファイルにコードが格納されています。このコードはデータセットを保存するたびに再生成されるので、編集はしないでください。 生成されるコードについて、以下に簡単にまとめます。この例では、「MyTab」という名前のテーブルを含む型指定されたデータセットが、「MyDS」という名前で生成されます。 型指定された
このとき、
を表します。 型指定された
厳密に型指定された
このとき、
を表します。 最後に、XMLの永続性に関連する特定のメソッドとプロパティが、厳密に型指定された
本稿の例では、2つの関連付けられたテーブルを使用します。およそ720行のコードを自動生成して、データオブジェクト層が構築されます。 データアクセス層データアクセスとビジネスロジックの間でも、必要に応じて層を分離することがあります。バックエンドのデータストレージエンジンが更新されたとき、それらの変更はすべてこの層で処理されます。データアクセス層では、データオブジェクトとデータストアとの連携を行い、データベースからデータセットを入力および更新するためのメソッドを提供します。また、この層によって、ビジネスロジックに必要なストアドプロシージャとのやり取りを行う場所が追加されます。この層を作成するには、プロジェクトに新しい項目を追加し、一覧からコンポーネントクラスオブジェクトを選択して、「OrdersDA」などの名前を指定します。すると、デザインサーフェイスが表示され、その他のオブジェクトを画面上で追加することができます。 ツールボックスのデータセクションで、データアダプタオブジェクト(SQL Serverの場合はSqlDataAdapter、その他のデータベースの場合はOleDataAdapter)をデザインサーフェイスにドラッグします。通常、ウィザードは自動的に起動しますが、起動しない場合はデータアダプタを右クリックして、[Configure Data Adapter]をクリックしてください。 最初の画面では接続を指定します。データベースへの既存の接続を選択するか、新しい接続を作成してください。2つ目の画面では、SQLまたはストアドプロシージャを作成するか、既存のストアドプロシージャを使用するかを選択できます。新しく作成する場合は、次の画面で必要なクエリを作成します。ストアドプロシージャを作成する場合は、各自の命名方法に従って名前を入力してください。なお、既存のストアドプロシージャを使用する場合は、3つ目の画面でストアドプロシージャ名を指定します。 SQLステートメントを使用する場合、3つ目の画面では、必要なデータをデータベースから返す デザインサーフェイスに戻り、先ほど作成したデータアダプタを選択します。プロパティ一覧の名前フィールドで、このオブジェクトに自分の命名方法に合った名前を指定してください(「daOrders」など)。次に、データ接続を調整する必要があります。作成した接続オブジェクトを選択し、プロパティで名前を「con」に変更します。接続文字列をハードコーディングする代わりに、この情報をapp構成ファイルに移動します。[Configurations]セクションのDynamicPropertiesエントリを展開し、その下(Dataセクションの下ではないことに注意)にあるConnectionStringプロパティを選択してください。プロパティの値の右にある、ビルドを実行する楕円形のボタンをクリックし、[map to a key in configuration file]チェックボックスをオンにして任意の名前を入力します(既定の名前を変更してください)。これで、「App.Config」ファイルにエントリが正しく作成され、実行時にそれを取得するためのコードが生成されます。 次に、先ほどと同じ手順で「Order Details」テーブルにデータアダプタをもう1つ追加し(必ず同じ接続を使用してください)、名前を「daOrderDetails」に変更します。 それぞれのデータアダプタを右クリックし、[Generate dataset]をクリックします。1つ目の手順で作成したデータセット「ProjectName.OrdersDO」を選択して、正しいテーブルが指定されていることを確認してください。[OK]をクリックすると、データアダプタからデータセットへのリンクに必要なすべてのコードがウィザードによって作成されます。 最後に、デザインサーフェイス上で右クリックし、[View Code]をクリックして表示をコードウィンドウに切り替えます。コンポーネントではなく型指定されたデータセットを継承するように、クラスの定義を変更してください。以上で、すべてのデータセットオブジェクトにビジネスオブジェクトからアクセスできるようになります。 Public Class OrdersDA Inherits OrdersDO ’System.ComponentModel.Component 生成されたコードは、次の折り畳み領域の中に隠されています。 +Component Designer generated code 生成されたコードに、データセットの入力と更新に必要な2つのメソッドを自分で追加する必要があります。以下のコードを追加してください。
Public Function FillDataSet() As DataSet
con.Open()
Me.daOrders.Fill(Me.Orders)
Me.daOrderDetails.Fill(Me.Order_Details)
con.Close()
Return Me
End Function
Public Function UpdateDataSet(Optional ByVal TableName _
As String = "All") As DataSet
con.Open()
If TableName = "Orders" Or TableName = "All" Then _
Me.daOrders.Update(Me.Tables("Orders"))
If TableName = "Order Details" Or TableName = "All" Then _
Me.daOrders.Update(Me.Tables("Order Details"))
con.Close()
End Function
’Add any other business object functionality here
End Class
最後に、すべてを保存してプロジェクトをビルドします。Sub Mainがないというエラーが表示されますが、これは次の手順で作成します。 生成されるコード「+Component Designer generated code」のセクションを展開すると、生成されたコードを確認できます。以下のコードが含まれています。
今回の2つのテーブルの場合、約150行のコードが生成されます。 ビジネス層 次に、ビジネスオブジェクトクラスを作成する手順に移ります。このクラスにはすべての検証ロジックとその他のビジネスロジックを含めます。Bizプロジェクトの場合は、クラス項目を「OrdersBO」という名前で新規作成します。コードウィンドウで、 注意
ビジネスロジックがそれほど多くなければ、データアクセスクラスに入れても構いませんが、ビジネス層の分離ができなくなります。
プレゼンテーション層Visual Studioには、アプリケーションのユーザーインターフェイスの部分を、マスタ-詳細のリレーションシップを表示しながら作成できるData Formウィザードがあります。 ソリューションエクスプローラで、これまでに使用してきたのと同じプロジェクトを右クリックし、[Add new item]をクリックします(ここでは、Data Formウィザードでビジネスオブジェクトを検出するために同じプロジェクトを使用します。コードは後で移動します)。一覧からData Formウィザードを選択して、フォームの名前に「OrdersWin」などを指定します。 次の画面で、プロジェクトに含まれる既存のデータセットが検索されます。このデータセットを使うことも、この画面で新しく作成することもできます。ここでデータセットを作成してもまったく問題ありませんが、データ層とプレゼンテーション層を混ぜると、N層アプリケーションのセオリーに反することになるので、ここではそのためにデータオブジェクトとビジネスオブジェクトを別に作成しています。 図4 Data Formウィザード(画面2) ![]() OrdersBOを選択すると(データオブジェクトではなくビジネスオブジェクトであることに注意)、ビジネスオブジェクト内に作成されている入力と更新のメソッドが一覧表示されるので、その中から、データセットの入力と更新に使うメソッドを選択します。 図5 Data Formウィザード(画面3) ![]() DataSetに複数のテーブルがある場合、ウィザードは画面をもう1つ表示します。この画面では、マスタテーブルと詳細テーブルを選択します。また、フォームに追加するフィールドも選択できます。 図6 Data Formウィザード(画面4) ![]() 最後に、1つの親をフォームビューに表示するのか、複数の親をグリッドビューに表示するのかを選択します。子レコードは画面下部のリンクされたグリッドに表示されます。 生成されるフォームは図7のようになります。このプロジェクトを実行すると、「Orders」と「Order Detail」の情報を操作するためのフォームになります。 ウィザードの最後のオプションで、親を1つだけ表示する設定にした場合は、1対多のリレーションシップを表示するフォームになり、Ordersレコードの間を移動するためのコントロールと、必要に応じてレコードを編集するためのコントロールが追加されます(図7を参照)。 アプリケーションをビルドして実行すると(プロジェクトのプロパティはOrdersWinフォームを起動するように設定しておきます)、最初にマスタ-詳細フォームが表示されます。リンクがどのように実行されたかを確認してください。詳細のグリッドのデータソースが 以上のように、このアプリケーションはわずかなコードを記述するだけで簡単に作成できます。これなら経験の浅い開発者でもアプリケーションをすぐに構築できますし、3層アーキテクチャの個々の層を分離することができます。 生成されるコードウィザードのコード生成機能により、各コントロールをデザインサーフェイスにドラッグしてプロパティを適切に指定したときと同じように、以下のコードが生成されます。
これらのコードのほとんどは、ビジュアルツールを使っても生成できますが、このウィザードを使用すれば20〜30分を節約できるうえに、優れたコーディングパターンが組み込まれます。生成されたコードは、合計でおよそ190行になりました。 一方で、このウィザードは非常に気難し屋です。このウィザードは、ビジネスオブジェクトクラスにすべてのプロパティを過不足なく作成しておかないと、そのクラスを検出してくれません(正しい組み合わせは、筆者もまだ確実にはわかりません)。また、入力と更新のメソッドには必ず正しいシグネチャを指定する必要があります。それができたとしても、グリッドが正しく生成されるとは限りません。 層の分離 分離する層は、アプリケーションの開発を始める前に作成しておくのがベストです。Windowsプロジェクトのすべての要素が用意できたら、「NorthwindBiz」という名前で新しいクラスライブラリプロジェクトを作成し、 まとめ現在ではアプリケーション生成のための優れたフレームワークやコード生成ツールが数多く販売されていますが、そのほとんどは、時間とお金をかけなければうまく使いこなすことができません。私はVisual Studio付属の生産性向上ツールを好んで使用しますが、このツールが展開するお粗末なプログラミング手法には満足していません。本稿で説明した手順がこの問題の解決に役立つはずです。 本稿では、正しく設計された実用的なアプリケーションモジュールを、およそ20分間で作成しました。生成したコードは1000行を超えましたが、自分で作成したコードはわずか10行ほどでした。 関連情報著者紹介David Catherman(David Catherman)
データベースアプリケーションのデザイン/開発に20年以上の経験を持ち、ここ4、5年は特にMicrosoft .NETとSQL Serverに仕事が集中している。現在はCMI Solutionsのアプリケーション設計者および上級開発者であり、Visual StudioとSQL Server 2005を使用している。.NETのMCPを取得し、現在MCSDを取得中。
メールの宛先はDCatherman@CMiSolutions.com。 |