エンティティセレクションとは、同じデータクラスに所属するエンティティへの一つ以上の参照を格納しているオブジェクトのことです。エンティティセレクションは、データクラスから0個、1個、あるいはX個のエンティティを格納することができます。ここでのXはデータクラスに格納されているエンティティの総数を表します。エンティティセレクションは"順列あり"あるいは"順列なし"状態のどちらかです(この点については以下に説明があります)。
エンティティセレクションは一般的にクエリを使用して作成されるか、あるいはリレーション属性から返されます。例:
brokers:=ds.Person.query("personType = broker")
このコードではbrokers にbroker タイプの人間が全て返されます。セレクションのエンティティにアクセスするためには、コレクション内の要素を昇順に調べるのに似ているシンタックスを使用します。例:
theBroker:=brokers[0]
entitySelection.orderBy( ) メソッドは提供されたソート条件に基づいた新しいエンティティセレクションを返します。例:
brokers:=brokers.orderBy("name")
このコードはbrokers にPersonエンティティからのエンティティセレクションを返しますが、名前順で並べ替えされたものが返されます。
また、リレーション属性を使用してエンティティセレクションを返すことも可能です。例:
brokers:=ds.Person.query("personType = broker")
brokerCompanies:=brokers.myCompany
このコードは、myCompany リレーション属性を使用して、brokers エンティティセレクション内の人間にリレートされた全ての企業をbrokerCompanies に代入します。エンティティセレクションに対してリレーション属性を使用するのは、リレートされたエンティティの連鎖を上下に検索するための、強力かつ簡単な方法です。
エンティティセレクション内のエンティティに対して何か繰り返しの操作を実行する(例えば特定の属性の値を取得して変更する)場合、For each...End for each 構造を使用することができます。例:
C_OBJECT(emp)
For each(emp;ds.Employees.all())
If(emp.Country="UK")
emp.salary:=emp.salary*1,03
emp.save()
End if
End for each
以下の方法を用いることで、エンティティセレクション型のオブジェクトを作成することができます:
データクラスに対して、異なるエンティティセレクションを好きなだけ同時に作成し、使用することができます。エンティティセレクションは、エンティティへの参照を格納しているに過ぎないという点に注意してください。異なるエンティティセレクションが同じエンティティへの参照を格納することも可能です。
注: エンティティセレクションはそれが作成されたプロセスにおいてのみ定義されます。ですから、例えばエンティティセレクションへの参照をインタープロセス変数に保存して、他のプロセスで使用するという使い方はできません。
全てのストレージ属性(テキスト、数値、ブール、日付)はエンティティセレクションのプロパティ、あるいはエンティティのプロパティとして利用可能です。エンティティセレクションと組み合わせて使用した場合、スカラー属性はスカラー値のコレクションを返します。例:
locals:=ds.Person.query("city = :1";"San Jose")
localEmails:=locals.emailAddress
このコードはlocalEmails 内に文字列としてのメールアドレスのコレクションを返します。
様々なクエリの方法に加えて、リレーション属性をエンティティセレクションのプロパティとして使用することで新しいエンティティセレクションを得ることもできます。例えば、以下のようなストラクチャーがある場合を考えます:

myParts:=ds.Part.query("ID < 100")
$myInvoices:=myParts.invoiceItems.invoice
最後の行は、myParts エンティティセレクション内のパーツにリレートしている商品が少なくとも1つは含まれている全ての請求書のエンティティセレクションを、$myInvoices 内に返します。リレーション属性がエンティティセレクションのプロパティとして使用されると、返される結果は、たとえ返されるエンティティが一つだけだとしても、常に新しいエンティティセレクションとなります。リレーション属性がエンティティセレクションのプロパティとして使用されてエンティティが何も返ってこない場合、返されるのは空のエンティティセレクションであり、null ではありません。
ローカルなエンティティセレクションには順列ありあるいは順列なしのどちらかがあります。基本的にはどちらのオブジェクトも似たような機能を持ちますが、そのパフォーマンスと利用できる機能に少し違いがあります。必要に応じて、どちらのタイプのエンティティセレクションを使用したいかを選択して下さい。
注: 4D Server からリモートのクライアントに返されるエンティティセレクションは常に順列ありとなります。
- 順列なしのエンティティセレクションはメモリ内のビットテーブルに基づいてビルドされています。順列なしのエンティティセレクションは、エンティティが実際にセレクション内にあるかどうかにかかわらず、データクラス内の各エンティティに対して1ビットを格納しています。各ビットは1か0に等しく、これはエンティティがセレクションに含まれているかを表します。いわば各エンティティのとてもコンパクトな表現と言えます。
結果として、順列なしのエンティティセレクションを使用したオペレーションはとても速いです。また、順列なしのエンティティセレクションはメモリ空間という面でも経済的です。順列なしのエンティティセレクションのバイト単位のサイズは、データクラス内のエンティティの数を8で割ったものと必ず等しくなります。例えば、10,000 エンティティを格納しているデータクラスの順列なしのエンティティセレクションを作成した場合、サイズは1,250 バイトとなり、RAM内では1.2KB程度となります。
その一方で、順列なしのエンティティセレクションを並べ替えることはできません。セレクション内のエンティティの位置を当てにすることはできないということです。また、セレクション内で同じエンティティに対して二つ以上の参照を持つことはできません。言い換えると、各エンティティは一度しか追加できないということです。
- 順列ありのエンティティセレクションはメモリ内で(エンティティ参照を格納する)倍長整数配列に基づいてビルドされています。エンティティへの各参照はメモリ内で4バイトのサイズをとります。このようなセレクションを処理し維持することは、順列なしのセレクションより長い時間と大きいメモリ空間を必要とすることになります。
その一方で、並べ替えをしたり再並び替えをすることが可能であり、エンティティの位置に依存することができます。また、同じエンティティに対して複数の参照を持つことも可能です。
以下の表は、それぞれのエンティティセレクションのタイプの主な特徴をまとめたものです:
機能 | 順列なしのエンティティセレクション | 順列ありエンティティセレクション 処理スピード | とても速い | 遅い メモリ内のサイズ | とても小さい | 大きい エンティティに対して複数の参照を格納する | 不可 | 可能 |
最適化の観点から、4D ORDA ではデフォルトでは通常順列なしのエンティティセレクションを作成しますが、orderBy( ) メソッドを使用した場合あるいは適切なオプション(以下参照)を使用した場合は除きます。このドキュメントでは、指定されている場合を除き、"エンティティセレクション"は"順列なしのエンティティセレクション"を指すこととします。
上記で書かれているように、デフォルトでは、ORDA はクエリやand( ) などの比較のオペレーションの結果として、順列なしのエンティティセレクションを作成・管理します。 順列ありのエンティティセレクションは、必要な場合において、あるいはオプションを使用して特別に要求した場合に限り作成されます。
順列ありのエンティティセレクションは以下のような場合に作成されます:
- セレクション(タイプを問わず)に対してorderBy( ) をした、あるいはデータクラスに対してorderBy( ) をした戻り値
- newSelection( ) メソッドにdk keep ordered オプションを渡した戻り値
順列なしのエンティティセレクションは以下のような場合に作成されます:
- セレクション(タイプを問わず)に対して標準のquery( ) をした、あるいはデータクラスに対してquery( ) をした戻り値
- オプションを使用しないでnewSelection( ) メソッドを使用した戻り値
- 任意の比較メソッドの結果。入力セレクションタイプは問いません: or( ), and( ), minus( )
順列ありのエンティティセレクションが順列なしのエンティティセレクションになった場合、重複したエンティティ参照は全て削除されます。
順列ありのエンティティセレクションを順列なしのものに変換したい場合、そのエンティティセレクションに対してand( ) オペレーションを適用するだけです。例:
mySel:=mySel.and(mySel)
エンティティセレクションオブジェクト自身は、オブジェクトとしてコピーすることはできません:
$myentitysel:=OB Copy(ds.Employee.all())
しかしながら、エンティティセレクションのプロパティは取得可能です:
ARRAY TEXT($prop;0)
OB GET PROPERTY NAMES(ds.Employee.all();$prop)