永続クラスの定義
永続クラスは、永続オブジェクトを定義するクラスです。ここでは、このようなクラスの作成方法について説明します。
このページで示されているサンプルは、Samples-Data (https://github.com/intersystems/Samples-DataOpens in a new tab) のものです。(例えば) SAMPLES という名前の専用ネームスペースを作成し、そのネームスペースにサンプルをロードすることをお勧めします。一般的な手順は、"サンプルのダウンロード" を参照してください。
永続クラスの定義
永続オブジェクトを定義するクラスを定義するには、そのクラスの プライマリ (最初の) スーパークラスを %PersistentOpens in a new tab にするかその他の永続クラスであることを確認してください。
例 :
Class MyApp.MyClass Extends %Persistent
{
}
パッケージからスキーマへのプロジェクション
永続クラスの場合は、パッケージが SQL スキーマとして SQL で表現されます。例えば、クラスが Team.Player (Team パッケージの Player クラス) である場合、対応するテーブルは Team.Player (Team スキーマの Player テーブル) です。
既定のパッケージは User です。これが SQLUser スキーマとして SQL で表現されます。したがって、User.Person という名前のクラスは、SQLUser.Person という名前のテーブルに対応します。
パッケージ名にピリオドが含まれる場合、ピリオドの代わりにアンダースコア (_) を使用します。例えば、MyTest.Test.MyClass クラス (MyTest.Test パッケージの MyClass クラス) は、MyTest_Test.MyClass テーブル (MyTest_Test スキーマの MyClass テーブル) になります。
SQL テーブル名がスキーマ名なしで参照される場合、既定のスキーマ名 (SQLUser) が使用されます。例えば、以下のコマンドがあります。
Select ID, Name from Person
上記は、以下と同じです。
Select ID, Name from SQLUser.Person
永続クラスのテーブル名の指定
永続クラスの場合、既定では、短いクラス名 (最後のピリオド後の名前の部分) がテーブル名になります。
別のテーブル名を指定する場合は、SqlTableName クラス・キーワードを使用します。以下に例を示します。
Class App.Products Extends %Persistent [ SqlTableName = NewTableName ]
InterSystems IRIS には、クラス名に対する制限はありませんが、SQL 予約語を SQL テーブルの名前に使用することはできません。このため、SQL 予約語である名前で永続クラスを作成すると、関連するテーブルに対してクエリを実行できなくなります。この場合は、ここで説明する方法を使用して、クラス名を変更するか、クラス名とは異なるテーブル名をプロジェクションに指定する必要があります。
ID の生成を制御する方法
オブジェクトを初めて保存するときに、そのオブジェクトの ID はシステムによって生成されます。ID は永続的になります。
既定では、InterSystems IRIS は ID に整数を使用します。この整数は、最後に保存したオブジェクトから 1 だけ増分されます。
特定の永続クラスを定義する際に、以下のいずれかの方法で ID が生成されるように定義できます。
-
ID は、クラスの特定のプロパティを基にすることができます (そのプロパティがインスタンスごとに一意である場合)。例えば、ドラッグ・コードを ID として使用することも可能です。この方法でクラスを定義するには、以下のようなインデックスをクラスに追加します。
Index IndexName On PropertyName [ IdKey ];
または (同様に)
Index IndexName On PropertyName [ IdKey, Unique ];
IndexName はインデックスの名前、PropertyName はプロパティの名前です。
この方法でクラスを定義すると、InterSystems IRIS は最初にオブジェクトを保存するときに、そのプロパティの値を ID として使用するようになります。さらに、InterSystems IRIS はプロパティの値を要求して、そのプロパティの一意性を強制します。指定されたプロパティに同じ値を持つ別のオブジェクトを作成して、新しいオブジェクトを保存しようとすると、InterSystems IRIS は以下のエラーを発行します。
ERROR #5805: ID key not unique for extent
さらに、InterSystems IRIS により、そのプロパティは将来にわたって変更できなくなります。つまり、保存したオブジェクトを開き、そのプロパティ値を変更し、変更したオブジェクトを保存しようとすると、InterSystems IRIS は以下のエラーを発行するようになります。
ERROR #5814: Oid previously assigned
このメッセージは、ID ではなく OID について言及しています。これは、基礎となるロジックが OID の変更を防止しているためです。OID は ID を基にしています。
-
ID は複数のプロパティに基づいたものにできます。この方法でクラスを定義するには、以下のようなインデックスをクラスに追加します。
Index IndexName On (PropertyName1,PropertyName2,...) [ IdKey, Unique ];
または (同様に)
Index IndexName On (PropertyName1,PropertyName2,...) [ IdKey ];
IndexName はインデックスの名前、PropertyName1、PropertyName2 などはプロパティの名前です。
この方法でクラスを定義すると、InterSystems IRIS は最初にオブジェクトを保存するときに、以下のように ID を生成するようになります。
PropertyName1||PropertyName2||...
さらに、InterSystems IRIS はプロパティの値を要求して、プロパティの指定の組合せの一意性を強制します。さらに、それらのプロパティはいずれも将来にわたって変更できなくなります。
リテラル・プロパティ (つまり、属性) に、連続する 1 対の垂直バー (||) が含まれている場合、そのプロパティを使用する IdKey インデックスは追加しないでください。この制限は、InterSystems SQL のメカニズムが動作するための方法に起因しています。IdKey プロパティ で || を使用すると、予測できない動作を起こす場合があります。
システムは OID も生成します。いずれの場合でも、OID は以下の形式になります。
$LISTBUILD(ID,Classname)
ID は生成された ID です。また、Classname はクラスの名前です。
サブクラスの SQL プロジェクションの制御
スーパークラス/サブクラスの階層内に複数の永続クラスが存在する場合、InterSystems IRIS は、それらのデータを 2 通りの方法で保存します。既定のシナリオは、極めて一般的です。
サブクラスの既定の SQL プロジェクション
クラス・コンパイラは、永続クラスを平坦化した表現を投影します。投影されたテーブルには、そのクラスの該当するフィールドのすべて (継承されたフィールドを含む) が含まれるようになります。したがって、サブクラスの SQL プロジェクションは、以下の項目で構成されたテーブルになります。
-
スーパークラスのエクステントに含まれるすべての列
-
サブクラスだけにあるプロパティに基づいたその他の列
-
サブクラスの保存済みインスタンスを表す行
さらに、既定のシナリオでは、スーパークラスのエクステントには、スーパークラスおよびそのスーパークラスのすべてのサブクラスの保存済みオブジェクトごとに 1 つのレコードが格納されます。各サブクラスのエクステントは、スーパークラスのエクステントのサブセットです。
例えば、SAMPLES 内には、永続クラスの Sample.Person と Sample.Employee があるとします。Sample.Employee クラスは Sample.Person を継承し、いくつかのプロパティが追加されます。SAMPLES では、どちらのクラスもデータを保存しています。
-
Sample.Person の SQL プロジェクションは、Sample.Person クラスの適切なプロパティをすべて含んでいるテーブルになります。Sample.Person テーブルには、Sample.Person クラスの保存済みインスタンスごとに 1 つのレコード、および Sample.Employee クラスの保存済みインスタンスごとに 1 つのレコードが格納されています。
-
Sample.Employee テーブルには、Sample.Person と同じ列が含まれています。さらに、Sample.Employee クラスに固有の列も含まれています。Sample.Employee テーブルには、Sample.Employee クラスの保存済みインスタンスごとに 1 つのレコードが格納されています。
これを表示するには、以下の SQL クエリを使用します。まず、Sample.Person のすべてのインスタンスをリストして、それらのプロパティを表示します。
SELECT * FROM Sample.Person
2 番目のクエリでは、Sample.Employee のすべてのインスタンスと、それらのプロパティをリストします。
SELECT * FROM Sample.Employee
Sample.Person テーブルには、1 から 200 の範囲の ID を持つレコードが含まれることに注意してください。101 から 200 までの範囲に含まれる ID を持つレコードは従業員であり、Sample.Employee テーブルは同じ従業員 (同じ ID と同じ追加列を持つ従業員) を示します。Sample.Person テーブルには、2 つの見かけ上のグループのみが配置されています。これは、SAMPLES データベースが人為的な方法で構築されているためです。Sample.Person テーブルが移入された後で、Sample.Employee テーブルが移入されます。
一般的に、サブクラスのテーブルには親クラスよりも多数の列と、少数の行が含まれます。サブクラスが親クラスを拡張するとき、サブクラスは通常、プロパティを追加するので、サブクラス内にはより多くの列があります。サブクラスには親よりもサブクラスのインスタンスが少ないので、多くの場合行数も少なくなります。
サブクラスの代替の SQL プロジェクション
既定のプロジェクションは最も便利なものですが、場合によっては、代替の SQL プロジェクションを使用することが必要になります。このシナリオでは、各クラスに独自のエクステントがあります。この形式のプロジェクションを行うには、スーパークラスの定義に以下を含めます。
[ NoExtent ]
例 :
Class MyApp.MyNoExtentClass [ NoExtent ]
{
//class implementation
}
このクラスの各サブクラスは、独自のエクステントを受け取ります。
この方法でクラスを作成し、その他のクラスのプロパティとして使用する場合は、"バリエーション : CLASSNAME パラメータ" を参照してください。