|
The Package Wizard |
Top Previous Next |
|
Package WizardはOracle Packageをカプセル化するDelphiクラスを生成するユーティリティを使うのに非常に強力で簡単です。 Package Wizardなしでは、適切なPL/SQLブロックと共にTOracleQueryを定義し、パラメーターに対して変数を定義し、変数値を設定、クエリーを実行、出力パラメーターか関数結果のために変数値を取得しなくてはいけません。TOraclePackageコンポーネントは既にこの処理を簡単にして、一度の呼び出しでプログラムユニットを呼びだし、パラメーターを渡すことができます。しかし、このコンポーネントは簡易化されたインターフェースのため、幾つかの制約があります。 Package Wizardsはこれらパッケージの関数とプロシージャーを内包するOracle Packageのselectionのためのクラスを作成します。 もしパラメーターがrecord型なら、これらのrecord型をカプセル化するクラスも生成します。 次のDepartment packageをサンプルとして考えて見ましょう: パッケージDepartmentの作成か置き換えは function Employee_Count(Deptno in dept.deptno%type) return binary_integer; procedure Select_Record(Dept_Record in out dept%rowtype); procedure Insert_Record(Dept_Record in dept%rowtype); procedure Update_Record(Dept_Record in dept%rowtype); procedure Delete_Record(Deptno in dept.deptno%type); procedure Get_Description(Deptno in dept.deptno%type, Description out CLOB); end Department;
ボタンの一度押すと、Package Wizardはこのパッケージのための2つのクラスを生成します: type DeptRowtype = class(TPLSQLRecord) public Deptno: Integer; Dname: string; Loc: string; procedure Assign(Source: TPLSQLRecord); override; end; TDepartment = class(TOracleCustomPackage) public function EmployeeCount(Deptno: Integer): Integer; procedure SelectRecord(var DeptRecord: DeptRowtype); procedure InsertRecord(DeptRecord: DeptRowtype); procedure UpdateRecord(DeptRecord: DeptRowtype); procedure DeleteRecord(Deptno: Integer); procedure GetDescription(Deptno: Integer; out Description: TLOBLocator); published property Name; property Session; property Cursor; property PackageSpecification; end;
DeptRowTypeクラスはプロシージャーに使われているdept%rowtypeパラメーターをカプセル化します。 TDepartmentクラスはDepartment packageをカプセル化し、6つのプログラムユニットの正確な表現を含みます。. これらの格納されたプログラムユニットを呼ぶためには、TDepartment クラスのインスタンスを作成する必要があり、 Sessionプロパティを設定し、そして対応する関数かプロシージャーを呼びます: Department := TDepartment.Create(nil); Department.Session := MainSession; EmpCount := Department.EmployeeCount(10); Department.Free;
見てわかるとおり、TdepartmentクラスはTOracleCustomPackageクラスから由来し、つまりTcomponentの子孫となります。 これは、これらOracle PackageをDelphiかC++Builder packageにインストールできることを暗に示し、コンポーネントパレットに置くことが出来ます。 これで設計時にTdepartmentコンポーネントをデータモジュールかフォームに置くことができ、TOracleSession コンポーネントにリンクさせることが出来ます。追加的コードなしに実行時に関数やプロシージャーを呼び出すことが出来て、Tdepartmentインスタンスをセットアップ・解放できます: EmpCount := MainDataModule.Department.EmployeeCount(10);
これ以上に簡単にすることは不可能でしょう。Oracle ServerソフトウェアはこれでDelphiかC++Builderプログラミング言語の自然な拡張となりました! 利点 Package Wizardを使うことには、TOracleQueryかTOraclePackage コンポーネントを使うより多くの利点があります。 いくつかの利点はわかりやすいものですが、それ以外は生成されたパッケージを使うときにわかるかもしれません:
Package Wizardを使う Package Wizardを開始するために、 DelphiやC++Builder IDEの'File | New' メニューを選んでください。そして'Oracle Package' アイコンをダブルクリックします。'Oracle'メニューへいき'Package Wizard' アイテムを選んでも構いません。ここで、パッケージ生成の最初の4ステップを示します。 Step 1 パッケージを選ぶ 、 クラスを作りたいと思うOracle PackageにアクセスできるOracleアカウントを使ってデータベースに接続します。 接続を確立したあと、パッケージの選択リストが現れます。'Show all packages' チェックボックスは、現在のOracleアカウントが持っているパッケージに限るように使われます。 ひとつもしくはそれ以上のパッケージを選択して、'Next'ボタンを押します。 Step 2 - インターフェースの翻訳ルールを定義 パッケージに対する次の翻訳ルールを定義できます: Always use variants as parameters 文字列、整数、ダブル、そしてTDateTimeパラメーターの代わりに、バリアントパラメーターを生成できます。 パラメーターが常にnullを表すという利点があります。. Integerかdoubleパラメーターに関して、nullとゼロの間には何も違いがありません。 このオプションの不利な点は、現在は名前に対してオーバーロード識別子を追加することによって(1, 2,など)で区別されるオーバーロードメソッドが生成できません。 他の不利な点は設計時にパラメーターのデータ型を素早く決定できません。Code Completionは常に'Variant'をdata型として表します。 Generate overloaded methods オーバーロードされたメソッドを生成するためにこのオプションを有効にします。 これはDelphiかC++Builder 4以降でのみ可能となります。 もしこのオプションが無効だと、オーバーロードされたプログラムユニットは名前にオーバーロード識別子をつけて区別されます。 Case このオプションはオブジェクト、メソッド、パラメーターの名前の大文字・小文字の使用を制御します。 4つの選択肢があります:
Remove underscores もしこのオプションが有効になっていると、 Oracle識別子内のアンダースコアが取り除かれます。これは通常'Capitalize' Caseオプションとのコンビネーションで使われます。 このコンビネーションを使うことで、INSERT_EMPLOYEEをInsertEmployeeに変換します。 Prefix objects with T DelphiとC++Builderでは、Tで始まるクラス名が慣習となっています。 このオプションを有効にすると、このプリフィックスがOracleパッケージ名に追加されます。 'Capitalize' Caseオプションと共に使うとパッケージDEPARTMENT は結果としてTdepartmentクラスとなります。 Prefix parameters with A メソッドのパラメーターにAを追加するコーディングスタイルを適用しているかもしれません。 このオプションを有効にしていると、生成されたパラメーター名にこのスタイルを適用します。 例えば、もしメソッドがDEPTNOパラメーターを持っていると、これはAdeptnoに変換されます。 このオプションを使うとパラメーターに対する予約語問題を解消することが出来ます(下記参照)。 これらプリファレンスのいくつかは生成されたクラスの名前に影響を与えます。 サンプルはこのページの下にあります。 Step 3 要素を確認し名前を変更する 翻訳ルールを定義したあと、 結果として出来たパッケージ、メソッド、そしてパラメータをみることになります。 この時点で、それらの名前を変更でき、個々のメソッドを除外できます。 もちろん後ほどソースを変更することも出来ます。 もしパッケージがパラメーターとしてのレコードのPL/SQL Tableを持つプログラムユニットを含んでいるなら、するとプログラムユニットは、Direct Oracle Accessから呼び出すことが出来ないので、除外されてしまいます。 名前のいくつかは、予約語の衝突を避けるためにPackage Wizard によって暗に変更されるかもしれません。 識別子名'object', 'type'や'program' はPL/SQLでは完全に正当です。しかし生成クラスに対してコンパイルエラーが発生するでしょう。 このような予約語に出会った場合、'1'が名前に追加されます。 Step 4 - ソースファイルを生成 ソースファイルを生成する前に、次のオプションを設定できます: Prefix database objects with schema name もしこのオプションを有効にすると、それぞれのデータベースオブジェクトはスキーマ名でプリフィックスされます。もしデータベースユーザーSCOTTがパッケージDEPARTMENTを所有していると、 結果は次のようになります: begin :result := scott.department.employee_count(deptno => :deptno); end;
もしアプリケーションのエンドユーザーのOracleアカウントが(publicかprivate)シノニムをこれらのオブジェクトに対して持っていない場合、そしてもしそれぞれのデータベース内でパッケージがSCOTTに所有されているならこれは適切な設定でしょう。 もしこのオプションを無効にすると、次のコードが生成されます: begin :result := department.employee_count(deptno => :deptno); end;
全てのユーザーがSCOTTアカウントを使ってデータベースに接続しているか、エンドユーザーのOracleアカウントがSCOTT.DEPARTMENTパッケージに対するシノニムをもっているかどうかを確認しなくてはなりません。 Generate thread safe code Theread-safeコードを生成するためにこのオプションを有効にします。 この結果、明示的にcritical sectionをプログラムすることなく、マルチスレッドから同時に呼び出されるパッケージクラスとなります。 もちろんこのオプションに関わるとても小さいパフォーマンスのトレードオフがあります。 Include package specification package specificationのソースは通常プログラムユニットと型に関するなんらかのドキュメントを含んでいます。 このオプションを有効にすることで、package specificationを生成されたソースファイルに含ませることが出来ます。 もしパッケージがコンポーネントとして生成されない場合 (下記参照)、するとソースファイル内にコメントとして含まれます。 もしコンポーネントとして生成されたら、specificationはPackageSpecification (read-only)プロパティとして含まれます。もちろん設計時に検査できます。 すぐそばにパッケージに関するドキュメントを持つほかに、 このオプションにはもう一つ利点があります。 クラスが再び生成されたパッケージの正確なイメージを常にもつことになります。 もしパッケージがある程度の頻度で変更される場合、これは有効な情報です。 Generate as components パッケージコンポーネントに対するレジストレーションコードを生成するためにこのオプションを有効にします。 こうすることで、これらをDelphiやC++Builderパッケージに追加し、コンポーネントパレットにも追加します。 パッケージをコンポーネントをとして扱うことは、パッケージインスタンスを明示的に作成し解放しなくてよくなるので、非常に便利になります。そして設計時にそれらをセッションにリンクすることが出来ます。設計時にPackageSpecificationプロパティを見ることができるという利点もあります。 Create component dcr file それぞれのパッケージクラスに対してデフォルトのアイコン(緑のパッケージシンボル)つきでリソースファイルを生成するためにこのオプションを有効にします。Image Editorを使ってパッケージの機能を視覚的に表すようにアイコンを変更できます。 Component palette もしパッケージコンポーネントをコンポーネントパレットに追加したいなら、存在するパレットの外にselectionを作るか、新しいパレットの名前を入力できます。 それはDelphiかC++Builder パッケージのインストール時に自動的に作成されます。 Path 生成しようとするソースファイルへのパスを入力するか選択します。もしこのフィールドを空白のままにすると、ソースファイルは現在開かれているプロジェクトのディレクトリに置かれます。 Filename 生成しようとしているソースファイルのファイル名を入力します。デフォルトの拡張しは.pasです。 Add to project 生成されたソースファイルを現在のプロジェクトに自動的に追加するためにこのオプションを有効にします。 Open in IDE 自動的に生成されたソースファイルをIDEに開くためにこのオプションを有効にします。 生成されたクラスを使う それぞれのOracleパッケージは、TOracleCustomPackageから派生したクラス内に実装されます。. このベースクラスは通常使うような機能は以下の2つのプロパティを除いて全く含まれていません:
Tcomponentクラスから由来したToracleCustomPackageクラス子孫です。それゆえそれぞれのパッケージはTcomponentからプロパティとメソッドを継承します。 TDepartmentインスタンスを作るために、セッションにリンクし、関数を呼び、そしてパッケージインスタンスを解放します。 次のコードを使うことが出来ます: Department := TDepartment.Create(nil); Department.Session := MainSession; Department.Cursor := crSQLWait; EmpCount := Department.EmployeeCount(10); Department.Free;
EmployeeCount関数の実行中は、マウスカーソルの形はSQLの砂時計になります。 パラメーター型 Scalar PL/SQLパラメーター型は、パッケージクラスのstring, integer, doubleそしてTdataTime data型になります。 もし'Always use variants for parameters' オプションを有効にすると、scalarパラメーターは代わりにバリアントで表されます。 複合PL/SQL パラメーター型は特定のクラスで表され、次の章で解説されます。 複合入力か入出力パラメーターに関しては対応するクラスのインスタンスを作る必要があり、メソッドに渡します。 出力パラメーターに関しては、対応するインスタンスはメソッド内部で作成され、この状況ではインスタンスを作る必要はありません。 これはインスタンスがオーバーライトされるので、メモリーリークを引起します。 全ての状況で、アプリケーションは責任をもってインスタンスを解放してください。 Ref Cursor このパラメーター型はTOracleQuery クラスによって表されます。メソッドを呼んだあと、 列を読み込む前にToracleQueryを実行してください。もしGetEmployeesプロシージャーがdepartmentを持つ全てのemployeeのためにカーソルを返す場合、 このメソッドを呼び出すコードはこのように成ります: Department := TDepartment.Create(nil); Department.Session := MainSession; Department.GetEmployees(10, EmpQuery); EmpQuery.Execute; while not EmpQuery.Eof do begin ShowMessage(EmpQuery.Field('ename')); EmpQuery.Next; end; EmpQuery.Free; Department.Free;
CLOB, BLOB and BFILE これら3 LOBデータ型はTLOBLocator クラスによって表されます。 入出力LOBパラメーターに関しては、正しい型のTLOBLocator インスタンスを作ってください(otCLOB, otBLOB, otBFILE)。Departmentパッケージが、departmentに対してdescripton CLOBを返すGetDescriptionプロシージャーを持っている場合、このCLOBを取得するコードはこのようになります: Department := TDepartment.Create(nil); Department.Session := MainSession; Department.GetDescription(10, Description); ShowMessage(Description.AsString); Description.Free; Department.Free;
オブジェクトとリファレンス Oracle8オブジェクト型とリファレンスはTOracleObjectとTOracleReferenceクラスによって表されます。 入力か入出力オブジェクトとリファレンスに対して、 作成したインスタンス正しい型名を持っているようにしてください。: Department := TDepartment.Create(nil); Department.Session := MainSession; Address := TOracleObject.Create(MainSession, 'TAddress', ''); Address.SetVariable('City', 'New York'); Department.SetAddress(10, Address); Address.Free; Department.Free;
PL/SQL Tables Package WizardはPL/SQL Tablesのscalar data型だけを持ちます。TPLSQLTableクラスはToracleCustomPackageに対してPL/SQL Tableを表します。 Department := TDepartment.Create(nil); Department.Session := MainSession; EmpTable := TPLSQLTable.Create(10, 0); EmpTable.Count := 3; EmpTable[0] := 7389; EmpTable[1] := 6711; EmpTable[2] := 8556; Department.DeleteEmployees(EmpTable); EmpTable.Free; Department.Free;
このサンプルでPL/SQL Tableは最高10要素に対して作られ、3つの要素で埋められ、DeleteEmployeesプロシージャーに渡されます。出力パラメーターに対して明示的にPL/SQL Tableを作りません。それでテーブルの最大値を制御できません。 最大文字列サイズはパッケージクラスに記されています。しかし最大テーブルサイズは実装によります。 パッケージクラスのユニットはDefaultPLSQLTableSize変数を含み出力パラメーターのテーブルサイズを定義します。初期値は100です。 注: 例えもし'Always use variants for parameters'オプションを無効にしていても、PL/SQL Tableの値は常にバリアントで表されます。 Record types パッケージ内でパラメーターとして使われるそれぞれのレコード型のために、対応sるうクラスはユニット内で作られます。 このクラスの名前はpackage specificationから派生し、抽象TPLSQLRecord クラスから由来します。 このベースクラスはCreate コンストラクタとAssign メソッドを定義します。もしdept%rowtypeパラメーターを使う場合、必要なコンポーネントを含む対応するDeptRowtypeクラスは宣言されます: DeptRowtype = class(TPLSQLRecord) public Deptno: Integer; Dname: string; Loc: string; procedure Assign(Source: TPLSQLRecord); override; end;
もし'Always use variants for parameters'オプションを有効にしていると、scalarレコードコンポーネントはバリアントで表されます。 複合レコードコンポーネントは次の章で解説されるクラスで表されます。record型のCreateコンストラクタはパラメーターとしてセッションを取ります。ですから、このレコード型インスタンス内にTLOBLocator, ToracleObjectとTOracleReferenceインスタンスを自動的に作成します。 SelectRecordプロシージャーを呼ぶために、次のコードを使うことが出来ます: Department := TDepartment.Create(nil); Department.Session := MainSession; DeptRecord := DeptRowtype.Create(MainSession); DeptRecord.Deptno := 10; Department.SelectRecord(DeptRecord); ShowMessage(DeptRecord.Dname); DeptRecord.Free; Department.Free;
DeptRecord.Freeデストラクタは、Createプロシージャー中、複合レコードコンポーネントのためにインスタンスを破棄します。 |