翻訳者 : Kazuyoshi Shimizu alsoft@naa.att.ne.jp |
データ オブジェクト
|
|
データ・オブジェクト・デザイン・スタジオ(
DODS )は、開発支援ツールです。DODSは、ほとんどの開発者が古い方法で書きたくないと思うコードを生成するオブジェクト指向のデザイン・ツールです。
DODSは、Enhydraアプリケーション・フレームワークを利用するアプリケーションの基礎を作るデータ層クラスの設計を可能にします。
またDODSは、それらのデータ層クラスに関する Java
ソースコードを生成し、それらをコンパイルします。
属性は、一つのデータ(例えば int, String, Date)か、他のデータ・オブジェクトへの参照を表わします。参照属性を使うことで、互いに連結したデータ・オブジェクトの関係を作ります。
まとまったデータ・オブジェクト定義は、プロジェクトファイルとして保存されます。あなたは、プロジェクトファイルを再び開いて、データ・オブジェクトへ変更を加えることができます。
定数でないデータ・オブジェクト中の各属性は、そのオブジェクトにより生成されたテーブル定義中の行を示します。さらに生成された各テーブルの定義は
'oid' と 'version' という Enhydra データベース・フレームワークにより使用される2つの行を含みます。
// method to instantiate a new 'dog' object not yet in the
dB
static DogDO createVirgin() { ... }
// methods to retrieve a 'dog' object from the 'dog' table
// using various forms of the primary key
static DogDO createExisting(String handle) { ... }
static DogDO createExisting(BigDecimal handle) { ... }
static DogDO createExisting(ObjectId handle) { ... }
// method returning the primary key value
// for this virgin/existing object
String getHandle() { ... }
// get/set methods for each Attribute of 'dog'
String getName() { ... }
void setName(String newValue) { ... }
int getAge() { ... }
void setAge(String newValue) { ... }
// methods to retrieve rows from database
DogBDO getNextBDO(); // retrieve one row at a time
DogBDO[] getBDOArray(); // retrieve all rows at once
Class DogBDO {
// methods to retrieve a 'dog' object from the 'dog' table
// using various forms of the primary key
static DogDO createExisting(String handle) { ... }
static DogDO createExisting(BigDecimal handle) { ... }
static DogDO createExisting(ObjectId handle) { ... }
// method returning the primary key value
// for this virgin/existing object
String getHandle() { ... }
// get/set methods for each Attribute of 'dog'
String getName() { ... }
void setName(String newValue) { ... }
int getAge() { ... }
void setAge(String newValue) { ... }
// commit() inserts this virgin object into the dB as a new
row,
// or updates the existing row with changes made with setXxx
void commit() { ... }
// delete() removes the dB row represented by this object
void delete() { ... }
注: BDO クラスは Lutris Technologies で行った初期のプロジェクトの産物です。その BOD クラスの機能は、その後にリリースされた DO クラスに(おそらく)組み込まれるでしょう。
DODS が生成したコードにおけるそのような変更は、 DODS が使用するソースコードテンプレートを変更することで行われます。詳しいことは
dods.conf ファイルを見てください。また、自身の設計に合うように、テンプレートを置き換えた設計者たちが送るメッセージに関する
Enhydra メーリングリストも見てください。
典型的な Enhydra アプリケーションに関するソースツリー配置は
'newapp'
ユーティリティを走らせることで見ることができます。たとえば、コマンド
cd /tmp
newapp myApp
は次のディレクトリ構造を示してくれます。
注:DODS において、各 XxxDO クラスは "myApp.data" パッケージ(またはサブパッケージ)中に作成しなければなりません。
あなたが、DODS が生成したコードを書くディレクトリを指定する場合は、DODS
は、指定したターゲットのディレクトリ上に、ディレクトリ構造にそむいて作成したパッケージの構造に、一致させようとします。もしそれらが一致したときには、
DODS は生成した Makefile を あなたのアプリケーションに合わせるように直します。そうでない場合、あなたが
DODS プロジェクトファイルを直し、コードと Makefile を再生成する都度、手作業で統合しなければなりません。
'Bob' と名づけられた犬に関する新しい 'dog' 列をデータベース中に作成します。::
DogBDO bob = DogBDO.createVirgin();サーブレットは、 オプション文字列として bobName を使用し、OPTION VALUE として bobHandle を使用したSELECT 文を含み、"Age" と名づけられた INPUT フィールドを含む HTML ページを組み立てます。そしてその HTML 文を獣医のブラウザへ送ります。 獣医は Bob の年齢を変更したいとします。それで、新しい年齢を入力し、 Bob と名づけられたオプションを選択し、サーブレットB へフォームを送信します。 サーブレットBは、dog テーブル中の Bob の行を表わした、一つの DogBDO を提示するために、選択された OPTION の VALUE.ハンドルを使用します。 そして Bob の新しい年齢がセットされ、行を更新します。
bob.setName( "Bob" );
bob.setAge( 1 );
bob.commit();
String bobName = bob.getName();
String bobHandle = bob.getHandle();
String dogHandle = getOptionFromRequest();
String newAge = getAgeFromRequest(); // get value of "Age" INPUT
field from request parameter
DogBDO selectedDog = DogBDO.createExisting( dogHandle );
selectedDog.setAge( newAge );
selectedDog.commit();
getOptionFromRequest( ) メソッドでは、要求されたパラメータから選択した OPTION のVALUE 属性を取得し、 getAgeFromRequest( ) メソッドでは、要求されたパラメータから選択した "Age" INPUT フィールドの値を取得します。
String dogName = // get INPUT name from request parameter
DogQuery q = new DogQuery();
q.setQueryName( dogName );
DogBDO selectedDog;
while ( null != ( selectedDog = q.getNextBDO() ) )
debugMsg( dogName + "'s age is " + selectedDog.getAge() );
DogQuery dq = new DogQuery();
dq.setQueryName( "Fido" );
QueryBuilder qb = dq.getQueryBuilder();
qb.addWhere( DogDO.age, 2, QueryBuilder.GREATER_OR_EQUAL );
qb.addWhere( DogDO.age, 4, QueryBuilder.LESS_OR_EQUAL );
qb.addOrderByColumn( DogDO.age );
// print SQL "select" statement before execution,
// compare against next example
qb.debug();
DogBDO[] youngFidos = dq.getBDOArray();
for ( int i = 0; i < youngFidos.length; i++ ) {
DogBDO dog = youngFidos[i];
print( dog.getName() + " is " +
dog.getAge() + " years old." );
}
QueryBuilder だけを使用して同じクエリを実行してください。あなたが単にデータレポートだけを生成しているときは(特に複数テーブルの結合をする場合)、QueryBuilder を直接使用したほうが、場合によっては一番簡単です。
Vector fields = new Vector(); // bind set of desired columns
fields.addElement( DogDO.name );
fields.addElement( DogDO.age );
QueryBuilder qb = new QueryBuilder( fields );
qb.addWhere( DogDO.name, "Fido" );
qb.addWhere( DogDO.age, 2, QueryBuilder.GREATER_OR_EQUAL );
qb.addWhere( DogDO.age, 4, QueryBuilder.LESS_OR_EQUAL );
qb.addOrderByColumn( DogDO.age, "ASCENDING" );
// print SQL "select" statement before execution,
// compare against previous example
qb.debug();
RDBRow row;
while ( null != ( row = qb.getNextRow() ) ) {
print( row.get( DogDO.name ).getString() + " is " +
row.get( DogDO.age ).getInteger() + " years old." );
}
上記で述べた、同じクエリを実行する便利なインターフェースを提供するために、 DODS が生成したクエリクラスを拡張しましょう:
class AdvancedDogQuery extends PersonQuery {
void setQueryAgeRange( int min, int max ) {
QueryBuilder qb = dq.getQueryBuilder();
qb.addWhere( DogDO.age, 2, QueryBuilder.GREATER_OR_EQUAL
);
qb.addWhere( DogDO.age, 4, QueryBuilder.LESS_OR_EQUAL
);
qb.addOrderByColumn( DogDO.age );
}
}
// using the extended query class
AdvancedDogQuery dq = new AdvancedDogQuery();
dq.setQueryName( "Fido" );
ad.setQueryAgeRange( 2, 4 );
DogBDO[] youngFidos = dq.getBDOArray();
for ( int i = 0; i < youngFidos.length; i++ ) {
DogBDO dog = youngFidos[i];
print( dog.getName() + " is " +
dog.getAge() + " years old." );
}
ツリーは、 DODS により作製されたデータオブジェクトを保持する、パッケージのディレクトリ構造です。設計とビルドが完了した時、このディレクトリ構成は、パッケージ中のデータオブジェクトに関連付けられた各ディレクトリ中に、適切な .java ファイルとともに作製されます。
テーブルは、データ・オブジェクトの属性を表示するために使われます。データ・オブジェクトがツリービューかグラフィカルビューのどちらかで選択されると、その属性がテーブル中に列挙されます。 たとえば、顧客(オブジェクト*)は電話番号や住所や多分名前までも持っているでしょう。それらおのおのの属性は、顧客オブジェクトが選択されたときにテーブル中に列挙されます。
このパッケージの配置は、'myApp' と名づけられたアプリケーションを、'newapp' ユーティリティで作成されたパッケージ階層にあわせます。 覚えておいてください。Java パッケージは小文字から始まります。 Java クラス名は大文字から始まります。
顧客と従業員はともに人々の型であるので、Person と名づけられた共通の属性を含む基本クラスを作成しましょう。
ツリーの中の "data" パッケージをクリック(選択)し、 Insert-->Data Object をクリックします。データオブジェクトエディタのダイアログが現れます。 名前に "Person" と設定します。 "Extends" を "Nothing" にしたままにしておきます。これは、 Person クラスがツリー中のどのクラスからも派生しないためです。
Package タブをクリックして "myApp.data" パッケージに新しい "Person" データ・オブジェクトができているのを確認します。(DODS Ver2.3 ではOKを押さない限り Person データオブジェクトがツリー上に生成されていなかった。*)
Database タブをクリックし、テーブル名を "person" にします。ここでは他の入力を無視します。
ダイアログの下にある OK をクリックすると、 "Person" データオブジェクトが グラフィック・ビューとツリーに表示されます。
"Person" データ・オブジェクトは青い丸のアイコンとしてツリー中に表示されます。もし、パッケージやデータオブジェクトの設定を変更したいならば、このアイコンをダブルクリックすると適切なエディタ・ダイアログが現れます。
Person は名前を持ちます。 DODS では、"name" は "Person" データオブジェクトの属性となります。DODSが PersonDO.java を生成したときは、"name" はデータメンバとなり、get と set のメソッドを持ちます。DODS が生成した PersonSQL.sql ファイルでは、"name" は"person"テーブル中の指定された行になります。
"name" 属性をPerson に追加するため、ツリーから Person を選択し、Insert-->Attribute をクリックします。アトリビュートエディタが立ち上がります。
Genaral タブの下で、Name に "name" を設定します。
Java タブの下で、Java Type を String にセットします。"name" 属性に関して初期値を与えることもできます。が、ここは空白にしておいたほうがいいでしょう。また、Javadoc text も与えられます。これは DODS が生成する PersonDO.java 中に現れれます。
Database タブの下では、dB Type を VARCHAR (文字列を保管するデータベースの型のようなもの)に設定します。ここであなたは "name" 行によるインデックスを "Person" データベーステーブルにつけたいかどうか、カラムに NULL 値を含めることができるようにするかどうか、"name" 値によるテーブル検索をしようとするかどうかを指定できます。名前による検索はしばしば有益なので、"Can be queried" チェックボックスをチェックしておきましょう。
もし、すべての Person が同じ名前だったならば、 "name" 値に定数を設定するでしょう。この場合、PersonalDO クラス中の "name" データメンバは "final" となり、"person" データベーステーブルは、"name" 行を持たないでしょう。当面 "Referenced DO" チェックボックスを無視しましょう。
"Person" データ・オブジェクトに "name" 属性を追加するため、アトリビュートエディタ・ダイアログの下にある OK ボタンをクリックします。テーブルパネルに、"name" 属性がすぐ現れます。色のついた絵文字で示されるテーブル行は、アトリビュートエディタで選ばれたチェックボックスを示しています。データベースタブ中にある "Can be queried" チェックボックスをチェックしたため、 'Q' の絵文字がこの属性を示すことに注意してください。これらの絵文字は、すばやく参照をできるようにするためのものであり、それらのボックスをクリックすることは属性の設定をすばやく切り替える方法です。それぞれのグリフが表す属性をの説明を見るため、テーブルビューのヘッダにある各グリフの上に、マウスを移動できます。多くの属性を持つデータオブジェクトを持っているときは、ヘッダの絵文字をクリックすることでテーブルの属性を並び替えることができます。
先に進み、同様に店舗オブジェクトを生成し、さらに名前の属性を付けましょう。
この例では、2種類の(サブクラスの)Personがあります。: それは顧客と従業員です。
Person を拡張して従業員データオブジェクトの例を生成します。
ツリーの中の Person を選択して、Insert-->Data Object とクリックします。データオブジェクトエディタが表示されます。新しいデータオブジェクトの名前に、"Employee" と入力します。"Extends" メニューで "myApp.data.PersonDO." を選択します。
エディタダイアログの下にある OK をクリックします。
ツリーパネルで、丸い Person のアイコンが青から黄色に変わりました。これは Person が抽象クラスになったことを表しています。
注:DODSでは、拡張されるデータオブジェクトは抽象でなければなりません。データオブジェクトが拡張されたときは、DODS はそれを自動的に抽象としてマークします。これはDODSにより生成されたデータオブジェクトクラスをデータベースに割り付けるための方法です。非抽象な "leaf" クラスだけがデータベース中にテーブルを持ちます。
従業員の青い丸のアイコンは 、"myApp.data"パッケージの代わりに "myApp"パッケージに含まれることも注意してください。私たちはエディタで従業員のパッケージをセットすることを忘れました。従業員アイコンを、"data"パッケージフォルダアイコンへ単にドラッグしてください。
店舗と従業員の間の1対多関係を確立します。
さて店舗と従業員の間の関係を確立しましょう。私たちの例では、ひとつもしくはそれ以上(すなわち、多く)の従業員たちが各店舗で働いています。そして、各従業員はただひとつの店舗で働きます。これを表現するためには、'employer' 属性を従業員に付加します。再度 Insert-->Attribute とクリックし、属性名に'employer を設定してください。Java タグの下で、この属性の型を myApp.data.EmployeeDO と設定してください。
データベースタグの下では、"Referenced DO must exist" チェックボックスをチェックします。これはデータベースに、顧客のアカウントマネジャは常に有効な従業員であるという ことを保証する、一貫した制約を課します。
OK をクリックします。さてグラフィカルビューパネルから顧客をクリックします。矢印が現れ、顧客から従業員へ位置付けします。これは今しがた生成したオブジェクト参照を示します。
DODS は 得られたStoreDO を参照する EmployeeDO オブジェクト配列を取得するために、 StoreBDO.getEmployeeDOArray() メソッドを生成します。
顧客データオブジェクトの例を作成し、店舗の多対多関連を確立しましょう。
Person から拡張した顧客オブジェクトを作成します。顧客データオブジェクトに口座番号の属性を付加します。;顧客アイコンを選択し、Insert-->Attribute をクリックします。属性の名前に "accountNumber" を設定し、 Java タブではそれを整数型にして、Darabase タブでは "Can be queried" をチェックします。
私たちのアプリケーション例に関して、どの顧客が各店舗を訪れたか、またどの店舗が各顧客により訪れられたかを知ることができるようにしたいとしましょう。これは多対多結合です。各顧客は多くの店舗を訪れます。また各店舗は多くの顧客が訪れます。この関係は単に顧客へ、店舗への参照属性またはその逆を与えるだけではできません。 そのような配置は、データベースに各顧客がただひとつの店舗を訪れ、各店舗はただ一人の顧客を持つことを示すだけです。多対多の関係を表現するには、特別な中間オブジェクトを作成する必要があります。
CustStore という名前のオブジェクトを作成します。 これに、CustomerDO を参照する 'customer' と名づけた属性を与えます。また StoreDO オブジェクトを参照する 'store' と名づけたもうひとつの属性を与えます。データベース中の各 CustStore オブジェクトのインスタンスは、与えられた顧客が与えられた店舗を訪れることを表します。
DODS は、与えられた CustomerDO により参照される StoreDO オブジェクトの配列を返す CustomerBDO.getStoreDOArray_via_CustStore() メソッドを生成します。また、DODS は、与えられた StoreDO により参照される CustomerDO オブジェクトの配列を返す StoreBDO.getCustomerDOArray_via_CustStore() メソッドを生成します。他の便利なメソッドは生成されたコードを見てください。
あなたは、すでにあるパッケージやデータ・オブジェクトや属性を選択して、Edit--> を選ぶことでそれらを編集できます。
また、あなたはパッケージやデータオブジェクトや属性を削除できます。しかし、そのアンドゥ機能は実行された最後の削除しか保持していません。
最後に、データ・オブジェクトのコードのすべてをビルドする準備ができたら、File-->Build All とクリックして下さい。このオプションは、作成したそのオブジェクトにエラーがない時に有効となります。もし、どこかにエラーがあったならば、Edit-->Find Next Error を選択すると、エラーのあるデータオブジェクトへ連れて行ってくれます。エラーは、赤い感嘆符でテーブル中に表示します。感嘆符をクリックしてエラーが何かを確認して下さい。
もし以前にプロジェクトを保存していないならば、プロジェクトの保存ダイアログが現れます。プロジェクトファイルのパスと名前を入力して OK を押します。
次に、あなたは Destory and Create New DODS Directory というダイアログに出会います。
この例では、次のディレクトリへ位置付け、
/tmp/myApp/myApp
そして、次のサブディレクトリを選択します。
data/
または、 /tmp/myApp/myApp/data と入力します。
警告:入力したパスが正しいことを、常に確認しなさい。 DODS はそのディレクトリとその直下にあるすべてを削除します。そして、あなたのプロジェクトの最新のパッケージ構造になるようディレクトリを再作成します。.
output/bin/dods
で、オプションパラメータ与えることができます。
dods [ project file [ output directory [ regen ] ] ]
もし、プロジェクトファイルを指定したならば、それは DODS が起動したときに自動的にオープンされます。
もし出力ディレクトリを指定したならば、ビルドボタンをクリックしたとき、既に選択されています。.
もし、第3のパラメータとして "regen" を指定したなら、DODS GUI は現れません。しかし、指名されたプロジェクトファイルはロードされ、コードジェネレータは指名された出力ディレクトリへソースコードを書き出します。"regen"
パラメータは、アプリケーションを完全に再構築するため、makefile から DODS
を起動するのに便利です。
DODS により生成された問合せクラスは、すべて QueryBuilder ヘルパクラスを使用します。setQueryAttributeName メソッドは、検索を実行すための SQL 選択コマンドを組み立てるため、 QueryBuilder.addWhereClause() メソッドを呼び出します。問合せクラスのインスタンス生成後、あなたは選択コマンドに付加的な句を追加するために QueryBuilder に関連付けられたインスタンスを得ることができます。(ある開発者たちは、このような付加機能の新しいメソッドを実装するために、拡張した問合せクラスを選びます)。付加の句を使用することで、選択コマンドはもっと複雑な検索が実行できます。
DB2 での注意: QueryBuilder.NOT_EQUALS 修飾子は DB2 データベースでは機能しない。代わりに 文字列 "<>" を使用しなさい。
create view count_people (total) as select count(*) from person
Count と呼ばれる他の DO を作成し、そのテーブル名を 'count_people' と指定し、'total' と命名された整数値の属性を追加し、その属性を "Can Be Queried" と印づけておきます。
そして、DODS に PersonDO, PersonBDO, PersonQuery, PeopleSQL.sql CountDO, CountBDO, CountQuery, CountSQL.sql クラスを生成させるため、ビルドボタンをクリックします。
CountSQL.sql ファイルを破棄し、DODS が生成した create_tables.sql ファイルから 'create table count_people' ステートメントを取り除きます。
データベース中にテーブルを定義するため、create_tables.sql ファイルを使用します。そして手作業で count_people ビューを作成します。(上の create view ステートメントを使います。)
CountQuery クラスは、あなたが行うどの問合せクラスの代用もできます。CountQuery により返される CountDO オブジェクトは、あなたがほしい 'total' を含みます。注: CountDO オブジェクトに対しては get メソッドだけしか呼び出してはいけません。
もし、あなたが Linux で JDK1.2 といっしょに DODS を動かしているならば、ちゃんと動作し、提供されたフォントは世界中で可読で、それらを含むディレクトリは実行可能です。Blackdown の JDK1.2 プレリリースは、彼らの最新のバージョンでたぶん修正されたであろうパーミッションの問題がありました。
もし、あなたが Linux か Windows のどちらかを走らせ、telnet で Unix (Solaris/Linux) サーバーに接続し、DODS を動作させたいとします。もしあなたのシステムが正しく構成されていない場合、恐ろしい表示の問題に陥るかもしれません。
もし、あなたのワークステーションが Linux システムならば、JDK1.2 は リモートの XFree86 サーバーで16 ビットカラーをサポートしないことに気づいたかもしれません。もし、16 ビットカラーで走らせているならば、おそらく 8 ビット色に変更したいでしょう。どうやってこれを行ったかをここに挙げます。(Red Hat でどうにかしておこないました。 - 私はどのようにして 異なるバージョンの Linux/XFree86 がパッケージされるか知りません。)たぶんもっといい方法があるに違いありませんが、いまだに見つけていません。
もしあなたが、font.properties ファイルを置き換えた後も、まだフォントが見つからないという問題を抱えているならば、Java が見つけられないフォントなしで DODS を続けていくか、あなた自身でその問題を修正しようとするかを取捨選択できます。sed を使えば、いくぶんか容易に font.properties を編集できます。
たとえば、もし私が Java コンソール上でフォントが見つからないという警告に出くわしたなら、UNIX マシンにtelnet で接続して次のことを行うでしょう。
注: X ウィンドウ下でそれらを開いているときは、ある場合には、ダイアログが空白で現れるかも知れません。 もしこのようなことがおきたら、コントロールを強制的に表示するため、ダイアログをリサイズすることがあります。
改定履歴
2001/01/03 1.00 初稿
2001/01/04 1.01 レイアウト修正