4D-jp 4D Japan Technical Support Team

共有エンティティセレクション

2020-11-10

ベータ公開されている18 R5では,エンティティセレクションの実装が変わり,デフォルトで共有オブジェクト版のエンティティセレクションが作成されるようになりました。共有エンティティセレクションは,新規プロセスまたはワーカーにパラメーターとして渡すことができます。

仕様の変更に伴い,query()all()のようなメソッドから返されたエンティティセレクションに対してentitySelection.add()を使用した場合,エラー1637が返されることになりました。共有エンティティセレクションは,リードオンリーだからです。まず,エンティティセレクションをコピーし,共有オブジェクトではないエンティティセレクションを作成してから,エンティティを追加する必要があります。

仕様が変更されたのは,ORDAコーディングの特性に関する理解が進み,将来を見越した最適化が図られたためです。

注記: ベータ版の情報です。リリース版では仕様が変更される可能性があります。

大抵のORDAアプリケーションでは,エンティティセレクションを作成した後,or() minus() and()のような「セット演算」に使用したり,query() slice() orderBy() のような「フィルター」で絞り込んだりするようなロジックが一般的です。列挙したメソッドは,いずれも新規エンティティセレクションを返し,元のエンティティセレクションは変更しません。別の言い方をすれば,オブジェクトとしてのエンティティセレクションはミュータブル(変更不可)です。

たとえば

$es:=ds.Company.query(…).orderBy(…).minus(…)

というコードは,3段階にわたってエンティティセレクションを絞り込んでいますが,その都度,返されたエンティティセレクションに基づいて新しいエンティティセレクションを作成しているのであり,単一のエンティティセレクションを縮小しているわけではありません。ドット記法を連鎖せずに書き換えれば,その点が明確になります。

$es1:=ds.Company.query(…)
$es2:=$es1.orderBy(…)
$es3:=$es2:.minus(…)

このようなクエリ処理であれば,エンティティセレクションがリードオンリーであっても実行できることに注目してください。

add()は,元のエンティティセレクションを変更する例外的なメソッドです。ORDAでユーザーインタフェースを実装するような場合に使用します。リードオンリーのエンティティセレクションにエンティティを追加することはできないので,OB CopyあるいはentitySelection.copy()であらかじめ共有ではないエンティティセレクションを作成しておき,リストボックス等のデータソースに設定するのがポイントです。

Form.company:=ds.Company.query(…).copy()
Form.company.add(…)
Form.company.add(…)

つまり,18 R5以降,ユーザーインタフェースに表示するエンティティセレクション,特に内容を更新する可能性があるエンティティセレクションは,all()query()で作成した後,仕上げにcopy()を実行する,というコーディングになります。

エンティティセレクションを作成するコマンドは,いずれも共有オブジェクトを返しますが,Create entity selectionだけは例外です。このコマンドは,共有エンティティセレクションを作成し,その参照を返すわけではありません。そうではなく,クラシックコードで作成された既存のカレントセレクションに対するエンティティセレクション型の参照を作成し,その参照を返します。元となったカレントセレクションをREDUCE SELECTIONした場合,対応するエンティティセレクションもリサイズされるのはそのためです。

ドキュメントの記述は「新規エンティティセレクションを返します」となっていますが,前述したように,新規に作成されるのは,エンティティセレクション型のオブジェクトであり,エンティティセレクションそのものではありません。この振る舞いは,命名セレクションからカレントセレクションを「作成」するUSE NAMED SELECTIONに似ています。

エンティティセレクションは,オブジェクトの参照なので,変更不可ということに決めれば,実体の代わりに参照を複製するだけで済みます。100万件の順列なしエンティティセレクションの実体は,100キロビットのスペースを占有することがあります。順列ありのエンティティセレクションであれば,エンティティ1個につき,4バイトです。共有エンティティセレクションの参照であれば,エンティティ数に関係なく,サイズはわずか8バイトで済みます。

プロセス間で受け渡しができるといっても,すぐには共有エンティティセレクションの効果的な用途が思い浮かばないかもしれません。4D Remoteのクライアントであれば,DIALOGコマンドの*オプションやFormオブジェクトを活用することにより,アプリケーションプロセスだけでユーザーインタフェースを実装することができます。そのため,別プロセスにエンティティセレクションを渡して処理するようなことは限定的です(集計処理など)。

共有エンティティセレクションは,将来を見越した仕様です。現在,どのプロセスからでもアクセスできるStorageという共有オブジェクトがあり,プロセス間でオブジェクトを共有することができますが,同じように,Webリクエスト間で共有できるSessionオブジェクトの開発が進められています。これが実現すれば,Webリクエスト間でエンティティセレクションを共有できるようになります。Webクライアント(ブラウザ)は,ひとつのセッションで多数のプロセスを使用し,サーバーと非同期でプリエンプティブに通信するので,エンティティセレクションをコピーする代わりに参照を使用すれば,メモリとCPUの負担が大幅に軽減できる,と期待されています。

詳細は4D Forumsで読むことができます。


関連記事

リンク