コレクションの定義
コレクションは、任意のオブジェクト・クラスのプロパティとして定義できます。スタンドアロン・コレクションを使用することにより、プロパティの外部でコレクションを定義することもできます。
コレクション・プロパティの定義
リストまたは配列のプロパティを定義するには、以下のプロパティ定義構文を使用します。
Property MyProp as list of Type;
Property MyProp as array of Type;
MyProp はプロパティ名です。Type は、データ型クラスまたはオブジェクト・クラスのどちらかです。
以下の例は、%StringOpens in a new tab 値のリストのプロパティを定義する方法を示しています。
Property Colors as list of %String;
以下のコードは、Doctor オブジェクトの配列のプロパティを定義する方法を示しています。
Property Doctors as array of Doctor;
InterSystems IRIS では、コレクション・プロパティを %Collection パッケージ内にクラスのインスタンスとして格納します。これらのクラスには、コレクションの操作に使用できるメソッドとプロパティが含まれます。
以下の表は、コレクション・プロパティの定義方法と、その格納に使用する %Collection クラスの概要です。
Note:
プロパティのタイプとして %Collection クラスを直接使用しないでください。例えば、以下のようなプロパティ定義を作成してはいけません。
Property MyProp as %Collection.ArrayOfDT;
スタンドアロン・コレクションの定義
コレクション・プロパティを定義する別の方法として、メソッドの引数や戻り値として使用するためにスタンドアロン・コレクションを定義できます。スタンドアロン・コレクションを定義するために、InterSystems IRIS® では、%Library パッケージに、コレクション・プロパティの格納に使用する %Collection クラスと同様の機能を提供するクラスが用意されています。
スタンドアロン・コレクションを作成するには、適切なクラスの %New() メソッドを呼び出し、そのクラスのインスタンスを取得します。次に、そのインスタンスのメソッドを使用して、コレクションの操作を実行します。例えば、以下のコードは、%Library.ListOfDataTypesOpens in a new tab クラスを使用して文字列のリストを作成し、3 つの要素をリストに挿入してから、リスト内の要素の数を表示します。
set mylist=##class(%ListOfDataTypes).%New()
do mylist.Insert("red")
do mylist.Insert("green")
do mylist.Insert("blue")
write mylist.Count()
以下の表は、スタンドアロン・コレクションの定義方法と、その作成に使用する %Library クラスの概要です。
リスト・コレクションの操作
以降のセクションの例は、リスト・プロパティを操作する方法を示していますが、同様の構文を使用してスタンドアロン・コレクションのリストを操作することができます。
リスト要素の挿入
要素をリストの末尾に挿入するには、Insert() メソッドを使用します。例えば、obj がオブジェクトへの参照であり、Colors が関連オブジェクトのリスト・プロパティであるとします。このプロパティの定義は以下のとおりです。
Property Colors as list of %String;
以下のコードは、3 つの要素をリストに挿入します。リストがそれまで空だった場合、これらの要素は位置 1、2、および 3 にそれぞれ配置されます。
do obj.Colors.Insert("Red") // key = 1
do obj.Colors.Insert("Green") // key = 2
do obj.Colors.Insert("Blue") // key = 3
要素をリスト内の特定の位置に挿入するには、InsertAt() メソッドを使用します。例えば、以下のコードは、obj の Colors プロパティの 2 つ目の位置に文字列 Yellow を挿入します。
do obj.Colors.InsertAt("Yellow",2)
これにより、このリストの要素の順序は "Red"、"Yellow"、"Green"、"Blue" になります。新しい要素は位置 2 に配置され、それまで位置 2 および 3 にあった要素 ("Green" および "Blue") が位置 3 および 4 に移動し、新しい要素の場所が作られます。
リスト要素の挿入は、オブジェクトに対しても同じように機能します。例えば、pat がオブジェクト参照であり、Diagnoses が関連オブジェクトのリスト・プロパティであるとします。このプロパティは、以下のように定義されています (PatientDiagnosis はクラスの名前です)。
Property Diagnoses as list of PatientDiagnosis;
以下のコードは、オブジェクト参照 patdiag に格納される、PatientDiagnosis の新しいクラス・インスタンスを作成し、このオブジェクトを Diagnoses リストの末尾に挿入します。
Set patdiag = ##class(PatientDiagnosis).%New()
Set patdiag.DiagnosisCode=code
Set patdiag.DiagnosedBy=diagdoc
Set status=pat.Diagnoses.Insert(patdiag)
リスト要素へのアクセス
リスト要素にアクセスするには、以下のコレクション・メソッドを使用します。
-
GetAt(key) – key で指定された位置にある要素の値を返します。
-
GetPrevious(key) – key の直前の位置にある要素の値を返します。
-
GetNext(key) – key の直後の位置にある要素の値を返します。
-
Find(value, key) – key の後から開始して、value に等しい次のリスト要素のキーを返します。
例えば、以下のコードは、リストを反復処理し、そのリストの要素を順番に表示します。コレクションの Count プロパティによって、反復処理する要素の数が決まります。
set p = ##class(Sample.Person).%OpenId(1)
for i = 1:1:p.FavoriteColors.Count() {write !, p.FavoriteColors.GetAt(i)}
リスト要素の変更
指定したキーにある値を変更するには、以下の構文で示すように、SetAt() メソッドを使用できます。
do oref.PropertyName.SetAt(value,key)
ここで、oref はオブジェクト参照であり、PropertyName はそのオブジェクトのリスト・プロパティの名前です。例えば、person.FavoriteColors は好きな色のリスト・プロパティであり、その要素として red、blue、および green があるとします。以下のコードは、リストの 2 つ目の色を yellow に変更します。
do person.FavoriteColors.SetAt("yellow",2)
リスト要素の削除
リスト要素を削除するには、RemoveAt() メソッドを使用します。例えば、person.FavoriteColors は好きな色のリスト・プロパティであり、その要素として red、blue、および green があるとします。以下のコードは、位置 2 にある要素 (blue) を削除します。
do person.FavoriteColors.RemoveAt(2)
これにより、このリストの要素の順序は red、green になります。それまで位置 3 にあった要素 (green) が位置 2 に移動し、削除された要素によって生じた空きが埋められます。
配列コレクションの操作
要素を配列に追加するには、SetAt() メソッドを使用します。例えば、myArray.SetAt(value,key) は、key の位置にある配列要素を、指定された value に設定します。以下のコードは、新しい色を RGB 値の配列に挿入します。
do palette.Colors.SetAt("255,0,0","red")
palette はこの配列を格納するオブジェクトへの参照、Colors は配列プロパティの名前、"red" は値 "255,0,0" にアクセスするキーです。
Important:
配列キーとして使用する値には、連続する 1 対の垂直バー (||) を含めないでください。この制限は、InterSystems SQL のメカニズムに起因しています。
SetAt() は、既存の要素の値を変更することもできます。例えば、以下のコードは、"red" キーに格納されている値を 16 進形式に変更します。
do palette.Colors.SetAt("#FF0000","red")
配列内のコンテンツを反復処理するには、キーを GetNext() メソッドに参照渡しします。これにより、キーと値の両方をループで反復処理できます。例えば、以下のコードは、文字列配列のキーと値を順番に書き込みます。要素は、キーのアルファベット順に並べられます。
set arr=##class(%ArrayOfDataTypes).%New()
do arr.SetAt("red","color")
do arr.SetAt("large","size")
do arr.SetAt("expensive","price")
set key=""
for {set value=arr.GetNext(.key) quit:key="" write !,key," = ",value}
color = red
price = expensive
size = large
コレクション・データのコピー
一方のコレクションにある項目を他方のコレクションにコピーするには、コピー先のコレクションの設定を、コピー元のコレクションの設定と同じものにします。 これにより、コピー元の内容が、コレクション自身の OREF ではなく、コピー先にコピーされます。 以下は、このコマンドの例です。
Set person2.Colors = person1.Colors
Set dealer7.Inventory = owner3.cars
ここで、person2、person1、dealer7、および owner3 は、すべてクラスのインスタンスで、Colors、Inventory、および cars は、すべてコレクションのプロパティです。このコードの 1 行目は、同じクラスにある 2 つのインスタンス間でデータをコピーし、2 行目は、互いに異なるクラスにあるインスタンスの間でデータをコピーします。
コピー先のコレクションがリストで、コピー元のコレクションが配列の場合、InterSystems IRIS では、配列のデータのみがコピーされます (キー値はコピーされません)。 コピー先のコレクションが配列で、コピー元のコレクションがリストの場合、InterSystems IRIS では、コピー先の配列にキー値が生成されます。このキー値は、コピー元リストの項目の位置に基づいた整数になります。
Note:
コレクションの間で OREF をコピーする方法はありません。データのコピーのみが可能です。
コレクション・プロパティの SQL プロジェクションの制御
このドキュメントで前述したように、永続クラスは SQL テーブルとして投影されます。このセクションでは、リスト・プロパティと配列プロパティが既定で投影される方法と、そのような SQL プロジェクションを変更する方法について説明します。
リスト・プロパティの既定のプロジェクション
既定では、リスト・プロパティは、複数の値を含む単一の列として SQL に投影されます。この列内の項目を検索するには、FOR SOME %ELEMENT 述語を使用します。例えば、以下のクエリは、FavoriteColors 列 (FavoriteColors リスト・プロパティのプロジェクション) に要素 'Red' が含まれる行を返します。
SELECT * FROM Sample.Person WHERE FOR SOME %ELEMENT (FavoriteColors) (%VALUE = 'Red')
または、%INLIST 述語を使用して、リスト内の特定の要素を検索したり、特定の要素が含まれないリストを検索したりすることもできます。例えば、以下のクエリは、FavoriteColors 列にリスト要素 'Red' が含まれない行を返します。
SELECT * FROM Sample.Person WHERE NOT ('Red' %INLIST (FavoriteColors))
特定のインスタンスのリストが何も要素を含まない場合、これは空文字列として投影されます (SQL NULL 文字列ではありません)。
配列プロパティの既定のプロジェクション
既定では、配列プロパティは子テーブルとして投影されます。この子テーブルは親テーブルと同じパッケージ内にあります。この子テーブルの名前は、以下のようになります。
tablename_fieldname
各項目の内容は次のとおりです。
例えば、Siblings という名前の配列プロパティが設定された Person クラスがあるとします。Siblings プロパティのプロジェクションは、“Person_Siblings” という名前の子テーブルです。
この子テーブルには、以下の列が含まれます。
-
親クラスの対応するインスタンスの ID が含まれる列。この列は、配列が含まれる親クラスの外部キーとして機能し、そのクラスに対応する名前が付けられます。投影される Person_Child テーブルでは、この列の名前は Person です。
-
各配列メンバの ID が含まれる element_key という名前の列。
-
各配列メンバの値が含まれる列。この列には、配列プロパティに対応する名前が付けられます。投影される Person_Child テーブルでは、この列の名前は Siblings です。
以下の表は、サンプル・エントリと、Siblings 子テーブルの生成された列名を示しています。
配列プロパティのサンプル・プロジェクション
Person |
element_key |
Siblings |
10 |
C |
Claudia |
10 |
T |
Tom |
12 |
B |
Bobby |
12 |
C |
Cindy |
12 |
G |
Greg |
12 |
M |
Marsha |
12 |
P |
Peter |
上の例で ID = 11 のインスタンスのように、親クラスのインスタンスが、空のコレクション (何も要素を含まないコレクション) を保持する場合、そのインスタンスの ID は子テーブルに表示されません。
親テーブルには、Siblings 列は含まれません。
配列メンバを含む列の数とコンテンツは、配列の種類によって異なります。
-
データ型プロパティの配列は、1 列のデータとして投影されます。
-
参照プロパティの配列は、1 列のオブジェクト参照として投影されます。
-
埋め込みオブジェクトの配列は、子テーブル内の複数列として投影されます。これらの列の構造については、“埋め込みオブジェクト・プロパティ” を参照してください。
また、各インスタンスの ID と各配列メンバの識別子は、子テーブルの一意のインデックスを構成します。親インスタンスが関連する配列を持っていない場合、子テーブルには関連するエントリがありません。
Note:
既定では、シリアル・オブジェクト・プロパティは、同じ方法で SQL に投影されます。
Important:
コレクション・プロパティが配列として投影される際には、プロパティに追加する可能性がある任意のインデックスに対して固有の要件があります。"SQL 最適化ガイド" の “コレクションのインデックス作成” を参照してください。InterSystems IRIS 永続クラスのインデックスの概要は、“永続クラスのその他のオプション” の章を参照してください。
Important:
配列コレクションによって投影された子テーブルの SQL トリガはサポートされていません。ただし、配列プロパティを更新した後、ObjectScript を使用して親オブジェクトを保存すると、該当するトリガが起動します。
コレクションの代替のプロジェクション
このセクションでは、STORAGEDEFAULT、SQLTABLENAME、および SQLPROJECTION の各プロパティ・パラメータを説明します。これらはコレクション・プロパティの格納方法と SQL への投影方法に影響を与えます。
STORAGEDEFAULT パラメータ
リスト・プロパティは子テーブルとして格納できます。また、配列プロパティは $LIST として格納できます。どちらの場合も、そのプロパティの STORAGEDEFAULT パラメータを指定します。
-
リスト・プロパティの場合、既定では、STORAGEDEFAULT が "list" になります。STORAGEDEFAULT に "array" を指定すると、そのプロパティは子テーブルとして格納および投影されます。以下に例を示します。
Property MyList as list of %String (STORAGEDEFAULT="array");
結果のプロジェクションの詳細は、“配列プロパティの既定のプロジェクション” を参照してください。
-
配列プロパティの場合、既定では、STORAGEDEFAULT が "array" になります。STORAGEDEFAULT に "list" を指定すると、そのプロパティはリストとして格納および投影されます。以下に例を示します。
Property MyArray as array of %String (STORAGEDEFAULT="list");
結果のプロジェクションの詳細は、“リスト・プロパティの既定のプロジェクション” を参照してください。
Important:
STORAGEDEFAULT プロパティ・パラメータは、コンパイラがクラスのストレージを生成する方法に影響します。クラス定義に指定のプロパティのストレージ定義が含まれていた場合、このプロパティ・パラメータはコンパイラによって無視されます。
SQLTABLENAME パラメータ
コレクション・プロパティが子テーブルとして投影される場合は、そのテーブルの名前を制御できます。そのためには、そのプロパティの SQLTABLENAME パラメータを指定します。以下に例を示します。
Property MyArray as array of %String(SQLTABLENAME = "MyArrayTable");
Property MyList as list of %Integer(SQLTABLENAME = "MyListTable", STORAGEDEFAULT = "array");
SQLTABLENAME パラメータは、プロパティが子テーブルとして投影されていない場合には効果がありません。
SQLPROJECTION パラメータ
既定では、コレクション・プロパティは子テーブルとして格納され、子テーブルとして投影もされますが、親テーブルでは使用できません。そのプロパティを親テーブルでも使用できるようにするには、プロパティの SQLPROJECTION パラメータを "table/column" と指定します。
例えば、以下のクラス定義について考えてみます。
Class Sample.Sample Extends %Persistent
{
Property Property1 As %String;
Property Property2 as array of %String(SQLPROJECTION = "table/column");
}
システムは、クラスで 2 つのテーブル (Sample.Sample および Sample.Sample_Property2) を生成します。
テーブル Sample.Sample_Property2 は、既定のシナリオどおり、配列プロパティ Property2 のデータを格納します。ただし既定のシナリオとは異なり、クエリは Sample.Sample テーブル内の Property2 フィールドを参照できます。例えば、以下のようになります。
MYNAMESPACE>>SELECT Property2 FROM Sample.Sample where ID=7
13. SELECT Property2 FROM Sample.Sample where ID=7
Property2
"1 value 12 value 23 value 3"
ただし、SELECT * クエリは、Property2 フィールドを返しません。
MYNAMESPACE>>SELECT * FROM Sample.Sample where ID=7
14. SELECT * FROM Sample.Sample where ID=7
ID Property1
7 abc