この特集のトップページへ
Chapter 6:ビジネスロジックの設計



6.2.1 新規顧客の登録
Business.CustomerコンポーネントのAddCutomerメソッドの実装
 以上でDataObj.CustomerコンポーネントのAddRecordメソッドの実装は完了とする。続いて,Business.CustomerコンポーネントのAddCustomerメソッドを実装する。

 Business.CustomerコンポーネントのAddCustomerメソッドを実装するときには,冒頭で示したList 6-1の雛形に対して,その処理を記述してゆく。Fig.6-3で示したように,Business.CustomerコンポーネントのAddCustomerメソッドの処理内容は,すでに実装してきたDataObj.Customerコンポーネントを実体化し,List 6-2に示したAddRecordメソッドを呼び出して顧客情報テーブルに新しいレコードを追加するというものである。

 まだDataObjプロジェクトは未完成であるものの,この段階でDataObjプロジェクトをコンパイルし,dllファイルを作成してシステムに登録しておいてもらいたい。なぜなら,Business.CustomerコンポーネントはDataObj.Customerコンポーネントを利用するので,DataObjプロジェクトの参照設定が必要となるからである。DataObjプロジェクトを開いている状態でVisual Basicの[ファイル]メニューから[DataObj.dllの作成]を選択すると,プロジェクトがコンパイルされ,dllファイルが作成される。そのあと,自動的にレジストリに登録され,参照設定が可能な状態になる(ただし,この時点ではCOM+としてではなくCOMとして登録される。COM+として登録する方法については,「●作成したコンポーネントの動作テスト」で説明する。

Businessプロジェクトの作成
 では,Business.Customerコンポーネントの実装準備に入ろう。Business.Customerコンポーネントを実装するためには,Viual BasicでBusinessという名前の新しいプロジェクト(ActiveX DLLプロジェクト)を作成する。具体的な手順としては,Fig.6-4に示したのと同様にしてActiveX DLLプロジェクトを新規作成し,プロジェクト名を“Business”に変更する(Fig.6-5を参照)。

 Businessプロジェクトを作成したら,次に参照設定をする。Business.Customerコンポーネントでは,あらかじめ作成しておいたDataObj.Customerコンポーネントを利用するため,参照設定ダイアログボックスで“DataObj”を選択する(Fig.6-11)。また,Business.CustomerコンポーネントではCOM+の機能も使うため,「COM+ Services Type Library」についても同様に参照設定しておく。

Fig.6-11 参照設定
fig6_11


One Point! 参照設定ダイアログボックス内の項目として表示される文字列は,プロジェクトのプロパティにおける[プロジェクトの説明]のところで設定した文字列である(Fig.6-5を参照)。[プロジェクトの説明]が未入力の場合には,プロジェクト名が表示される。

 余談ではあるが,DataObjを参照設定すると,List 6-2で実装したDataObj.CustomerコンポーネントのAddRecordメソッドや,List 6-3で実装したErrorcode列挙型が正しく公開されていることを,オブジェクトブラウザで確認することができる(Fig.6-12)。

Fig.6-12 オブジェクトブラウザでDataObjを参照したところ
fig6_12

AddCustomerメソッドの実装
 プロジェクトの設定がすんだところで,Business.CustomerコンポーネントのAddCustomerメソッドの実装に移る。

 Business.Customerコンポーネントを実装するには,まずCustomerという名前のクラスモジュールを作る。それには,Fig.6-6に示したのと同じように新しいクラスモジュールを追加し,追加したクラスモジュールの名前を“Customer”に変更すればよい。

 Customerクラスモジュールを追加したならば,Business.Customerコンポーネントのデフォルトのトランザクションの要件を[新しく必要]に設定するため,CustomerクラスモジュールのMTSTransactionModeプロパティを[RequiresNewTransaction]に変更する(Fig.6-13)。

Fig.6-13 CustomerクラスモジュールのMTSTransactionModeプロパティの変更
fig6_13

 MTSTransactionModeプロパティを[RequiresNewTransaction]に変更したことにより,Business.Customerコンポーネントが実体化されると,常に新しいトランザクションが開始されるようになる。すでにDataObj.Customerコンポーネントを[トランザクションが必要]に設定しているため(Fig.6-7),実体化されたBusiness.CustomerオブジェクトからDataObj.Customerコンポーネントを実体化して利用した場合,両者は同じトランザクション内で実行されるようになる。すなわち,Business.CustomerオブジェクトとDataObj.Customerオブジェクトのどちらか一方がアボートした場合には,データベースへの操作はロールバックされ,元の状態に戻るようになる。


One Point!5.5.3 プログラムの開発」で説明したように,MTSTransactionModeプロパティは,COM+に登録されたときのデフォルトのトランザクション状態を決めるものでしかない。よって,管理者がBusiness.CustomerコンポーネントやDataObj.Customerコンポーネントのプロパティにおいてトランザクションの状態を変更した場合には,上記のように動作するとは限らない。

 以上で設定が終了したところで,Business.CustomerコンポーネントにAddCustomerメソッドを実装することにする。結局のところ,DataObj.Customerコンポーネントを実体化してAddRecordメソッドを呼び出すだけである。そのプログラムは,List 6-8のようになる。

 List 6-8は,基本的には,31行目でDataObj.Customerコンポーネントを実体化し,そのDataObj.CustomerコンポーネントのAddRecordメソッドを34行目で呼び出し,顧客情報テーブルに新しいレコードを付け加えるというものである。

 ただし,事前に19〜28行目において,このメソッドを呼び出したユーザーが“Sales”という名前のロールに属しているかどうかを調べ,属していないのであれば,Err.Raiseメソッドを使って実行時エラーを発生させている(ただし,19〜28行目の実装は,COMコンポーネントの汎用性の問題から,あとで削除する。その理由については,「●作成したコンポーネントの動作テスト」で説明する)。

 「3.1 構築するアプリケーションモデル」でも説明したように,本サンプルアプリケーションでは,顧客を新規に登録できるのは営業部に属するユーザーに限っている。そこで,あらかじめ営業部という部署を示すSalesという名前のロールを用意し(実際にロールを用意する方法についてはすぐあとで説明する),そこに営業部に属する実ユーザーを登録しておく(Table 6-3参照)。このように設定しておくと,25行目のIf文によってSalesロールに属さないユーザー,いい換えれば営業部に属さないユーザーから呼び出されたときには実行時エラーが発生し,新規顧客登録を抑制することができる。なお,20〜23行目の処理は,コンポーネント管理ツールにおけるCOM+アプリケーションのプロパティのセキュリティページにおいて,[このアプリケーションへのアクセスチェックを行う]が有効であるかどうかを調べ,有効でなければ実行時エラーとするための処理である(「4.3.2 ロールの有効化」ならびに「5.2.1 ロールの判定」を参照)。

注意ObjectContextオブジェクトのIsCallerInRoleメソッドは,そのメソッドを呼び出したユーザーが特定のロールに属しているかどうかを調べるものである。COM+の管理下にある最初のCOMオブジェクトのメソッド(ルートオブジェクトのメソッド)を呼び出したユーザーを調べるものではない。本サンプルアプリケーションの場合には,Business.CustomerオブジェクトからDataObj.Customerオブジェクトを呼び出すというビジネスロジック部分が2階層になっている。だが,呼び出したユーザーが特定のロールに属するかどうかを調べるために,Business.Customerオブジェクトから間接的に呼び出されるDataObj.Customerオブジェクト内でIsCallerInRoleメソッドを呼び出してはならない。この場面では,直接プレゼンテーション層から呼び出されるBusiness.Customerオブジェクト内でIsCallerInRoleメソッドを呼び出すようにする。なぜなら,DataObj.Customerオブジェクト内でIsCallerInRoleメソッドを呼び出した場合,「プレゼンテーション層から呼び出したユーザーが特定のロールに属するかどうか」ではなく,「Business.Customerオブジェクトから呼び出したユーザー(すなわち,COM+アプリケーションの実行ユーザー)が特定のロールに属するかどうか」を調べることになってしまうからである(「5.2.2 実際に実行するユーザー」を参照)。

 ところで,List 6-8の22行目ならびに27行目では,それぞれErr_NOSECUREという定数とErr_CANTACCESSという定数を使っている。これらの定数は,BusinessErrorという名前の列挙型としてList 6-9のように別途定義することにする。

 BusinessError列挙型は,DataObjプロジェクトで定義したErrorCode列挙型と同様に,エラーコードを定義して利用するために用意した列挙型である。BusinessError列挙型は,Businessプロジェクトの適当な場所に記述しておけばよい。ここでは,Customerクラスモジュールの冒頭に記載することにする。


One Point!List 6-9を見るとわかるように,BusinessError列挙型の先頭のエラーコードは“vbObjectError + 513 + 10000 + 1”となっている。一方,DataObj.Customerコンポーネントにおけるエラーコードを定義したErrorCode列挙型(List 6-3)の先頭のエラーコードは,“vbObjectError + 513 + 100 + 1”である。ここで,仮にErrorCode列挙型の最大値を“vbObjectError + 513 + 9999”までと制限するならば,Errorcode列挙型とBusinessError列挙型で重複した値を使うことがなくなる。
 プレゼンテーション層が呼び出すのは,Business.CustomerコンポーネントのAddCustomerメソッドであり,プレゼンテーション層からはDataObj.Custmerコンポーネントは見えないようになっている。すなわち,プレゼンテーション層側では,エラーがBusiness.Customerコンポーネントで発生したのか,それともDataObj.Customerコンポーネントで発生したのかを区別することが事実上できない。どのようなエラーが発生したのかをプレゼンテーション層側で判断するには,エラーコードが唯一の手がかりとなる。もし,Business.CustomerコンポーネントとDataObj.Customerコンポーネントの同じエラーコードに別の意味を割り当ててしまうと,プレゼンテーション層はどのようなエラーが発生したのかを判断できなくなってしまう。そのため,Business.Customerコンポーネントが発生させるエラーコードを定義するBusinessError列挙型と,DataObj.Customerコンポーネントが発生させるエラーコードを定義するErrorCode列挙型とのあいだで,重複した値を持たないようにすることは重要となるのである。逆にいえば,Business.CustomerコンポーネントとDataObj.Customerコンポーネントで同じ意味を持つエラーについては,統一感を持たせるため,同じエラーコードを使ったほうがよい。

prevpg.gif Chapter 6 10/92 nextpg.gif