メインコンテンツまでスキップ
バージョン: 21 R3

データモデルクラス

ORDAでは、データモデルの上に高レベルクラス関数を作成することができます。 これによってビジネス指向のコードを書き、APIのように "公開" することができます。 データストア、データクラス、エンティティ、およびエンティティセレクションはそれぞれ、関数を持つことのできるクラスオブジェクトとして提供されています。

たとえば、選択中の社員より給与の高い社員一覧を返す getNextWithHigherSalary() 関数を EmployeeEntity クラスに作成したとします。 この関数は簡単に呼び出すことができます:

$nextHigh:=ds.Employee.get(1).getNextWithHigherSalary()

これらの関数はローカルデータストアだけでなく、クライアント/サーバーやリモートアーキテクチャーでも使用することができます:

//$cityManager はリモートデータストアへの参照です
Form.comp.city:=$cityManager.City.getCityName(Form.comp.zipcode)

この機能により、4D アプルケーションのビジネスロジックをまるごと独立したレイヤーに保存し、高レベルのセキュリティで簡単に管理・利用することができます:

  • わかりやすく使いやすい関数のみを公開し、その裏にある構造の複雑性を "隠す" ことができます。

  • 構造が発展した場合には影響を受ける関数を適応させるだけで、クライアントアプリケーションは引き続き透過的にそれらを呼び出すことができます。

  • デフォルトでは、データモデルクラス関数 (計算属性関数 含む) および エイリアス属性 はすべて、リモートアプリケーションに対して 非公開 に設定されており、RESTリクエストで呼び出すことはできません。 公開する関数やエイリアスは exposed キーワードによって明示的に宣言する必要があります。

各データモデルオブジェクトに関わるクラスは、4D によって あらかじめ自動的に作成 されます。

アーキテクチャー​

ORDA では、4D クラスストア を介して公開される 汎用クラス と、cs クラスストア で公開される ユーザークラス が提供されています:

ORDA データモデルクラスはすべて cs クラスストアのプロパティとして公開されます。 次の ORDA クラスが提供されています:

クラス例次によってインスタンス化されます
cs.DataStorecs.DataStoreds コマンド
cs.DataClassNamecs.EmployeedataStore.DataClassName, dataStore["DataClassName"]
cs.DataClassNameEntitycs.EmployeeEntitydataClass.get(), dataClass.new(), entitySelection.first(), entitySelection.last(), entity.previous(), entity.next(), entity.first(), entity.last(), entity.clone()
cs.DataClassNameSelectioncs.EmployeeSelectiondataClass.query(), entitySelection.query(), dataClass.all(), dataClass.fromCollection(), dataClass.newSelection(), entitySelection.drop(), entity.getSelection(), entitySelection.and(), entitySelection.minus(), entitySelection.or(), entitySelection.orderBy(), entitySelection.orderByFormula(), entitySelection.slice(), Create entity selection

ORDA ユーザークラスは通常のクラスファイル (.4dm) としてプロジェクトの Classes サブフォルダーに保存されます。

ORDA データモデルユーザークラスのオブジェクトインスタンスは、それらの親クラスのプロパティや関数を使うことができます:

クラスの説明​

履歴
リリース内容
21 R3server キーワードのサポート。
19 R4Entity クラスのエイリアス属性
19 R3Entity クラスの計算属性
18 R5データモデルクラス関数は、デフォルトでは REST に公開されません。 新しい exposed および local キーワード。

DataStore クラス​

4D のデータベースは、自身の DataStore クラスを cs クラスストアに公開します。

  • 親クラス: 4D.DataStoreImplementation
  • クラス名: cs.DataStore

DataStore クラス内には、ds オブジェクトを介して使用する関数を作成することができます。

例題​

// cs.DataStore class

Class extends DataStoreImplementation

Function getDesc
$0:="社員と会社を公開するデータベース"

この関数は次のように使えます:

$desc:=ds.getDesc() //"社員と会社を..."

DataClass クラス​

ORDA で公開されるテーブル毎に、DataClass クラスが cs クラスストアに公開されます。

  • 親クラス: 4D.DataClass
  • クラス名: cs.DataClassName (DataClassName はテーブル名です)
  • 例: cs.Employee

例題​

// cs.Company クラス


Class extends DataClass

// 収益が平均以上の会社を返します
// Company DataClass にリレートしているエンティティセレクションを返します

Function GetBestOnes()
$sel:=This.query("revenues >= :1";This.all().average("revenues"));
$0:=$sel

全会社データから平均以上の会社データをエンティティセレクションに抽出するには次を実行します:

var $best : cs.CompanySelection
$best:=ds.Company.GetBestOnes()

info

計算属性 は Entity クラス において定義されます。

リモートデータストアの例​

次の City カタログをリモートデータストアとして公開しています:

City クラス は API を提供しています:

// cs.City クラス

Class extends DataClass

Function getCityName($zipcode : Integer) -> $cityName : Text
var $zip : 4D.Entity

$zip:=ds.ZipCode.get($zipcode)
$cityName:=""

If ($zip#Null)
$cityName:=$zip.city.name
End if

クライアントはまず、リモートデータストアのセッションを開始します:

$cityManager:=Open datastore(New object("hostname";"127.0.0.1:8111");"CityManager")

クライアントアプリケーションは API を使い、たとえばフォームに入力された郵便番号 (zipcode) に合致する都市を取得することができます:

Form.comp.city:=$cityManager.City.getCityName(Form.comp.zipcode)


EntitySelection クラス​

ORDA で公開されるテーブル毎に、EntitySelection クラスが cs クラスストアに公開されます。

  • 親クラス: 4D.EntitySelection
  • クラス名: DataClassNameSelection (DataClassName はテーブル名です)
  • 例: cs.EmployeeSelection

例題​

// cs.EmployeeSelection クラス


Class extends EntitySelection

// このエンティティセレクションから平均値より高い月給をもらっている従業員を抽出します

Function withSalaryGreaterThanAverage() : cs.EmployeeSelection
return This.query("salary > :1";This.average("salary")).orderBy("salary")

任意の社員エンティティセレクションより、給与が平均以上の社員を取得するには:

$moreThanAvg:=ds.Company.all().employees.withSalaryGreaterThanAverage()
info

エンティティセレクションを制限する フィルターは DataClass クラス 内で定義されます。

Entity クラス​

ORDA で公開されるテーブル毎に、Entity クラスが cs クラスストアに公開されます。

  • 親クラス: 4D.Entity
  • クラス名: DataClassNameEntity (DataClassName はテーブル名です)
  • 例: cs.CityEntity

Class constructor​

エンティティクラスに対して class constructor を定義することができます。 クラスコンストラクターはエンティティがメモリ内に作成されるたびに呼び出され、これを使用して一部の値を初期化することができます。

詳細な情報についてはClass constructor を参照してください。

計算属性​

Entity クラスでは、専用のキーワードを使用して 計算属性 を定義することができます:

  • Function get attributeName
  • Function set attributeName
  • Function query attributeName
  • Function orderBy attributeName

詳細については、計算属性 を参照してください。

エイリアス属性​

Entity クラスでは、Alias キーワードを使用して エイリアス属性 を定義することができます (通常はリレート属性を対象に定義します):

Alias attributeName targetPath

詳細については、エイリアス属性 を参照してください。

例題​

// cs.CityEntity クラス

Class extends Entity

Function getPopulation() : Integer
return This.zips.sum("population")


Function isBigCity(): Boolean
// 関数 getPopulation() をクラス内で使用することができます
return This.getPopulation()>50000

次のように関数を呼び出すことができます:

var $cityManager; $city : Object

$cityManager:=Open datastore(New object("hostname";"127.0.0.1:8111");"CityManager")
$city:=$cityManager.City.getCity("Caguas")

If ($city.isBigCity())
ALERT($city.name + " は大きな町です。")
End if

定義規則​

データモデルクラスを作成・編集する際には次のルールに留意しなくてはなりません:

  • 4D のテーブル名は、cs クラスストア 内において自動的に DataClass クラス名として使用されるため、cs 名前空間において衝突があってはなりません。 特に:

    • 4D テーブルと ユーザークラス名 に同じ名前を使用してはいけません。 衝突が起きた場合には、ユーザークラスのコンストラクターは使用不可となります (コンパイラーにより警告が返されます)。
    • 4D テーブルに予約語を使用してはいけません (例: "DataClass")。
  • クラス定義の際、Class extends ステートメントに使用する親クラスの名前は完全に合致するものでなくてはいけません (文字の大小が区別されます)。 たとえば、EntitySelection クラスを継承するには Class extends EntitySelection と書きます。

  • データモデルクラスオブジェクトのインスタンス化に new() キーワードは使えません (エラーが返されます)。 上述の ORDA クラステーブルに一覧化されている、通常の インスタンス化の方法 を使う必要があります。

  • 4D クラスストア のネイティブな ORDA クラス関数を、データモデルユーザークラス関数でオーバーライドすることはできません。

プリエンプティブ実行​

コンパイル済みの状態では、データモデルクラス関数は次のように実行されます:

  • シングルユーザーアプリケーションでは、プリエンプティブまたはコオペラティブプロセス で実行されます (呼び出し元のプロセスに依存します)。
  • クライアント/サーバーアプリケーションでは、プリエンプティブプロセス で実行されます (ただし、local キーワードが使用されている場合は、シングルユーザーの場合と同様に、呼び出し元プロセスに依存します)。

クライアント/サーバーで動作するように設計されているプロジェクトでは、データモデルクラス関数のコードがスレッドセーフであることを確認してください。 スレッドセーフでないコードが呼び出された場合、実行時にエラーが発生します (シングルユーザーアプリケーションではコオペラティブ実行がサポートされているため、コンパイル時にはエラーが発生しません)。

Class constructor​

履歴
リリース内容
20 R10追加

シンタックス​

// Entity class
Class constructor()
// コード
注

クラスコンストラクター関数コードにおいては、終了キーワードはありません。 4D ランゲージは、次のFunction キーワードまたはクラスファイルの終了を持って、自動的に関数のコードの終わりを検知します。

ORDA クラスコンストラクター関数は、作成された方法に関わらず、新規エンティティがメモリ内に作成された直後にトリガーされます。 これは例えばカスタムのID など、エンティティインスタンス化時に初期値を設定するのに有用です。

この関数は エンティティレベル でのみ設定可能です。 コンストラクター関数は、1つのエンティティクラスに 1つしか存在できません (そうでない場合はエラーが返されます)。

ORDA クラスコンストラクター関数は、引数を受け取ることも返すこともしません。 しかし、 This.を使用して属性値を初期化することができます。 コンストラクターによって初期化された値は、対応する属性がコードによって値が入力される場合にはそれによって上書きされるということに注意してください。

注

ORDA クラスコンストラクター関数は、ユーザークラスコンストラクター関数 と似ていますが、以下の点において違います:

  • コンストラクターには引数を渡すことはできません
  • shared、 session または singleton キーワードを使用することはできません
  • 関数内で Super キーワードを呼び出すことはできません
  • クラスコンストラクターは、エンティティに new() 関数を使用することでは呼び出せません(エンティティは特定の関数でしか作成することはできません、以下参照)。

クラスコンストラクター関数をトリガーするコマンド​

Class constructor 関数は、以下のコマンドと機能によってトリガーされます:

注記
  • entity.clone() 関数はエンティティクラスコンストラクターをトリガーしません。
  • 4D クラシックランゲージ言語コマンドまたは標準アクションを使用して4D データベースレベルで作成されたレコードは、エンティティクラスコンストラクターをトリガーしません。

リモート構成​

リモート設定を使用する場合、以下の原則に注意する必要があります: クライアント/サーバー では、呼び出しコードの実行場所においては、クライアントまたはサーバーのどちらからでも関数を呼び出すことが可能です。 クライアント上で呼び出された場合、クライアントが新規エンティティを保存しようとして、サーバーのメモリ上に作成するために更新リクエストを送信したときにはもう一度トリガーされることはありません。

警告

dataClass.fromCollection() のような関数は大量のエンティティを一度を作成し、結果としてエンティティクラスコンストラクターをトリガーしうるため、パフォーマンス上の理由から、コンストラクターコードに過度に時間を消費するような処理を実行しないように注意する必要があります。 リモート設定においては(以下参照)、コードはサーバーに対して複数のリクエストをトリガーしてはいけません。

例題 1​


//cs.BookingEntity class
Class constructor()

This.departureDate:=Current date
This.arrivalDate:=Add to date(Current date; 0; 0; 2)

例題 2 (図): クライアント/サーバー​

例題 3 (図): Qodly - 標準アクション​

例題 4 (図): Qodly - 標準アクションと新規作成エンティティの値を更新​

例題 5 (図): Qodly - 関数内でインスタンス化されたエンティティ​

計算属性​

概要​

計算属性は、計算をマスクするデータ型を持つデータクラス属性です。 標準的な 4Dクラスは、get (ゲッター) および set (セッター) アクセサー関数 を用いて、計算プロパティの概念を実装しています。 ORDA のデータクラス属性はこれを利用し、さらに query と orderBy の 2つの関数で機能を拡張しています。

計算属性には最低限、その値がどのように算出されるかを記述した get 関数が必要です。 属性にゲッター関数が定義されている場合、4D は対応するストレージスペースをデータストアに作成せず、代わりに属性がアクセスされるたびに関数のコードを実行します。 属性がアクセスされなければ、コードも実行されません。

計算属性は、その属性に値が割り当てられたときに実行される set 関数を実装することもできます。 セッター関数は、割り当てられた値をどのように処理するかを記述します。通常は、1つ以上のストレージ属性や、場合によっては他のエンティティにリダイレクトします。

ストレージ属性と同様に、計算属性も クエリ に含めることができます。 デフォルトでは、ORDA のクエリで計算属性が使用された場合、その属性はエンティティ毎に一度計算されます。 場合によっては、これで十分です。 しかし、特にクライアント/サーバーにおいてはパフォーマンスを向上させるため、実際のデータクラス属性に基づいた query 関数を計算属性に実装することで、それらのインデックスの恩恵を受けることができます。

同様に、計算属性を 並べ替え に含めることもできます。 デフォルトでは、ORDA の並べ替えで計算属性が使用された場合、その属性はエンティティ毎に一度計算されます。 クエリと同様に、実際のデータクラス属性に基づいた orderBy 関数を計算属性に実装することで、パフォーマンスを向上させることができます。

計算属性の定義​

計算属性を作成するには、データクラスの Entity クラス に get アクセサー関数を定義します。 計算属性は、データクラス属性およびエンティティ属性として自動的に利用可能になります。

その他の計算属性の関数 (set、query、orderBy) も、Entityクラスに定義することができます。 これらの関数の定義は任意です。

計算属性の関数内において、This はエンティティを指します。 計算属性は、他のデータクラス属性と同様に使用することができます。つまり、Entity クラス や EntitySelection クラス の関数によっても同様に処理されます。

ORDA の計算属性は、デフォルトでは 公開 されません。 計算属性を公開するには、get 関数 の定義に exposed キーワードを追加します。

get および set関数は、クライアント/サーバー処理を最適化するために、local プロパティを持つこともできます。

Function get <attributeName>​

シンタックス​

{local | server} {exposed} Function get <attributeName>({$event : Object}) -> $result : type
// コード

ゲッター 関数は、attributeName 計算属性を宣言するために必須です。 attributeName がアクセスされるたびに、4D は Function get のコードを評価し、$result 値を返します。

計算属性は、他の計算属性の値を使用することができます。 再帰的な呼び出しはエラーになります。

ゲッター 関数は、$result パラメーターに基づいて、計算属性のデータ型を定義します。 以下の結果の型が可能です:

  • スカラー (テキスト、ブール、日付、時間、数値)
  • オブジェクト
  • ピクチャー
  • BLOB
  • エンティティ (例: cs.EmployeeEntity)
  • エンティティセレクション (例: cs.EmployeeSelection)

$event パラメーターは、以下のプロパティが含みます:

プロパティ型説明
attributeNameText計算属性の名称
dataClassNameTextデータクラスの名称
kindText"get"
戻り値Variant任意。 スカラー属性が Null を返すようにするには、このプロパティを Null値で追加します。
注

local および server キーワードのより詳細な情報については、local and server の章を参照してください。

例題​

  • fullName 計算属性:
Function get fullName($event : Object)-> $fullName : Text

Case of
: (This.firstName=Null) & (This.lastName=Null)
$event.result:=Null //Null を返すのにresult を使用
: (This.firstName=Null)
$fullName:=This.lastName
: (This.lastName=Null)
$fullName:=This.firstName
Else
$fullName:=This.firstName+" "+This.lastName
End case
  • 計算属性は、エンティティにリレートされた属性に基づいて定義することができます。
Function get bigBoss($event : Object)-> $result: cs.EmployeeEntity
$result:=This.manager.manager

  • 計算属性は、エンティティセレクションにリレートされた属性に基づいて定義することができます。
Function get coWorkers($event : Object)-> $result: cs.EmployeeSelection
If (This.manager.manager=Null)
$result:=ds.Employee.newSelection()
Else
$result:=This.manager.directReports.minus(this)
End if

Function set <attributeName>​

シンタックス​


{local | server} Function set <attributeName>($value : type {; $event : Object})
// コード

セッター 関数は、属性に値が割り当てられたときに実行されます。 この関数は通常、入力値を処理し、その結果を 1つ以上の他の属性に転送します。

$value パラメーターは、属性に割り当てられた値を受け取ります。

$event パラメーターは、以下のプロパティが含みます:

プロパティ型説明
attributeNameText計算属性の名称
dataClassNameTextデータクラスの名称
kindText"set"
valueVariant計算属性によって処理されるべき値
注

local および server キーワードのより詳細な情報については、local and server の章を参照してください。

例題​

Function set fullName($value : Text; $event : Object)
var $p : Integer
$p:=Position(" "; $value)
This.firstname:=Substring($value; 1; $p-1) // "" if $p<0
This.lastname:=Substring($value; $p+1)

Function query <attributeName>​

シンタックス​

Function query <attributeName>($event : Object)
Function query <attributeName>($event : Object) -> $result : Text
Function query <attributeName>($event : Object) -> $result : Object
// コード

このメソッドは 3種類のシンタックスを受け入れます:

  • 最初のシンタックスでは、$event.result オブジェクトプロパティを通じてクエリ全体を処理します。

  • 2番目と 3番目のシンタックスでは、関数は $result に値を返します:

    • $result がテキストの場合、それは有効なクエリ文字列でなければなりません。
    • $result がオブジェクトの場合、次の 2つのプロパティを含まなければなりません:
    プロパティ型説明
    $result.queryTextプレースホルダー (:1, :2, など) を使った有効なクエリ文字列
    $result.parametersCollectionプレースホルダーに渡す値

query 関数は、計算属性を使用するクエリが開始されるたびに実行されます。 インデックス付きの属性を利用することで、クエリをカスタマイズしたり最適化したりすることができます。 計算属性に対して query 関数が実装されていない場合、検索は常にシーケンシャルにおこなわれます (get <AttributeName> 関数によるすべての値の評価に基づきます)。

以下の機能はサポートされていません:

  • エンティティ、またはエンティティセレクション型の計算属性に対する query 関数の呼び出し
  • 結果のクエリ文字列における order by キーワードの使用

$event パラメーターは、以下のプロパティが含みます:

プロパティ型説明
attributeNameText計算属性の名称
dataClassNameTextデータクラスの名称
kindText"query"
valueVariant計算属性によって処理されるべき値
operatorTextクエリ演算子 (query クラス関数も参照ください)。 とりうる値:
  • == (と等しい; @ はワイルドカード)
  • === (と等しい; @ はワイルドカードでない)
  • != (と等しくない; @ はワイルドカード)
  • !== (と等しくない; @ はワイルドカードでない)
  • < (小さい)
  • <= (less than or equal to)
  • > (大きい)
  • >= (以上)
  • IN (含まれる)
  • % (キーワードを含む)
  • 戻り値Variant計算属性によって処理されるべき値。 4D がデフォルトクエリ (計算属性では常にシーケンシャル) を実行するようにしたい場合は、このプロパティに Null を渡します。

    関数が $result に値を返し、$event.result プロパティにも別の値が割り当てられている場合、$event.result が優先されます。

    例題​

    • fullName 計算属性のクエリ:
    Function query fullName($event : Object)->$result : Object

    var $fullname; $firstname; $lastname; $query : Text
    var $operator : Text
    var $p : Integer
    var $parameters : Collection

    $operator:=$event.operator
    $fullname:=$event.value

    $p:=Position(" "; $fullname)
    If ($p>0)
    $firstname:=Substring($fullname; 1; $p-1)+"@"
    $lastname:=Substring($fullname; $p+1)+"@"
    $parameters:=New collection($firstname; $lastname) // 二つの項目を格納したコレクション
    Else
    $fullname:=$fullname+"@"
    $parameters:=New collection($fullname) // 単一の項目を格納したコレクション
    End if

    Case of
    : ($operator="==") | ($operator="===")
    If ($p>0)
    $query:="(firstName = :1 and lastName = :2) or (firstName = :2 and lastName = :1)"
    Else
    $query:="firstName = :1 or lastName = :1"
    End if
    : ($operator="!=")
    If ($p>0)
    $query:="firstName != :1 and lastName != :2 and firstName != :2 and lastName != :1"
    Else
    $query:="firstName != :1 and lastName != :1"
    End if
    End case

    $result:=New object("query"; $query; "parameters"; $parameters)

    ユーザーのテキスト入力に基づくクエリでは、セキュリティ上の理由からプレースホルダーを使用することが推奨されています (query() の説明 参照)。

    呼び出しコードの例:

    $emps:=ds.Employee.query("fullName = :1"; "Flora Pionsin")
    • この関数は age (年齢) 計算属性に対するクエリを処理し、パラメーターを含むオブジェクトを返します:
    Function query age($event : Object)->$result : Object

    var $operator : Text
    var $age : Integer
    var $_ages : Collection

    $operator:=$event.operator

    $age:=Num($event.value) // 整数
    $d1:=Add to date(Current date; -$age-1; 0; 0)
    $d2:=Add to date($d1; 1; 0; 0)
    $parameters:=New collection($d1; $d2)

    Case of

    : ($operator="==")
    $query:="birthday > :1 and birthday <= :2" // d1 の後、d2より前か等しい

    : ($operator="===")

    $query:="birthday = :2" // d2 = 計算された2つ目の日付(= 誕生日の日付)

    : ($operator=">=")
    $query:="birthday <= :2"

    //... その他の演算子の場合


    End case


    If (Undefined($event.result))
    $result:=New object
    $result.query:=$query
    $result.parameters:=$parameters
    End if

    呼び出しコードの例:

    // 20歳から21歳(の1日前)の間の年齢の人物を検索
    $twenty:=people.query("age = 20") // "==" の場合を呼び出す

    // 今日ちょうど20歳の人物を検索
    $twentyToday:=people.query("age === 20") // people.query("age is 20") と同等

    Function orderBy <attributeName>​

    シンタックス​

    Function orderBy <attributeName>($event : Object)
    Function orderBy <attributeName>($event : Object)-> $result : Text

    // コード

    orderBy 関数は、計算属性で並べ替えされるたびに実行されます。 これにより、計算属性で並べ替えることができます。 たとえば、fullName を名字、名前の順にソートしたり、逆に名字、名前の順にソートすることができます。 計算属性に対して orderBy 関数が実装されていない場合、並べ替えは常にシーケンシャルにおこなわれます (get <AttributeName> 関数によるすべての値の評価に基づきます)。

    Entity クラス、または EntitySelection クラス型の計算属性に対する orderBy 関数の呼び出しは サポートされていません。

    $event パラメーターは、以下のプロパティが含みます:

    プロパティ型説明
    attributeNameText計算属性の名称
    dataClassNameTextデータクラスの名称
    kindText"orderBy"
    valueVariant計算属性によって処理されるべき値
    operatorText"desc" または "asc" (デフォルト)
    descendingBoolean降順の場合は true, 昇順の場合は false
    戻り値Variant計算属性によって処理されるべき値。 4D にデフォルトソートを実行させるには、Null を渡します。

    operator と descending プロパティのどちらを使っても構いません。 これは、基本的にプログラミングのスタイルの問題です (例題参照)。

    orderBy 文字列は、$event.result オブジェクトプロパティまたは関数の戻り値である $result のどちらでにも返すことができます。 関数が $result に値を返し、$event.result プロパティにも別の値が割り当てられている場合、$event.result が優先されます。

    例題​

    次のような条件分岐のコードを書くことができます:

    Function orderBy fullName($event : Object)-> $result : Text
    If ($event.descending=True)
    $result:="firstName desc, lastName desc"
    Else
    $result:="firstName, lastName"
    End if

    また、次のような短縮コードを書くこともできます:

    Function orderBy fullName($event : Object)-> $result : Text
    $result:="firstName "+$event.operator+", "lastName "+$event.operator


    場合によっては条件分岐のコードが必要です:

    Function orderBy age($event : Object)-> $result : Text

    If ($event.descending=True)
    $result:="birthday asc"
    Else
    $result:="birthday desc"
    End if

    エイリアス属性​

    概要​

    エイリアス 属性は、ターゲット 属性と呼ばれるデータモデルの別の属性を元に定義されます。 ターゲット属性には、リレートデータクラス (リレートレベルは無制限) または同じデータクラスのものを使用できます。 エイリアス属性はデータではなく、ターゲット属性へのパスを格納します。 データクラスには、必要な数だけエイリアス属性を定義することができます。

    エイリアス属性は、N対Nリレーションを扱うのに便利です。 実装の詳細ではなくビジネスの概念を扱ってコードやクエリを作成できるため、これらの可読性が向上します。

    エイリアス属性の定義​

    データクラス内にエイリアス属性を作成するには、データクラスの Entityクラス において Alias キーワードを使用します。

    Alias <attributeName> <targetPath>​

    シンタックス​

    {exposed} Alias <attributeName> <targetPath>

    attributeName は、プロパティ名の命名規則 に準拠している必要があります。

    targetPath は、"employee.company.name" のような、1つ以上のレベルを含む属性パスです。 ターゲット属性が同じデータクラスに属している場合、targetPath は属性名となります。

    エイリアスは、他のエイリアスのパスに使用することができます。

    計算属性 もエイリアスパスに使用することができますが、パスの最後のレベルとしてのみ使用できます。そうでない場合は、エラーが返されます。 たとえば、"fullName" 計算属性がある場合、"employee.fullName" というエイリアスパスは有効です。

    ORDA のエイリアス属性は、デフォルトでは 公開されません。 リモートリクエストでエイリアスを利用するには、Alias キーワードの前に exposed キーワードを追加する必要があります。

    エイリアス属性の使用​

    エイリアス属性は読み取り専用です (同じデータクラスのスカラー属性に基づく場合は例外です; 最後の例題参照)。 エイリアス属性は、次のようなクラス関数において、ターゲット属性パスの代わりに使用することができます:

    Function
    dataClass.query(), entitySelection.query()
    entity.toObject()
    entitySelection.toCollection()
    entitySelection.extract()
    entitySelection.orderBy()
    entitySelection.orderByFormula()
    entitySelection.average()
    entitySelection.count()
    entitySelection.distinct()
    entitySelection.sum()
    entitySelection.min()
    entitySelection.max()
    entity.diff()
    entity.touchedAttributes()

    エイリアス属性はサーバー上で計算されることに留意してください。 リモート環境において、エンティティのエイリアス属性を更新するには、エンティティをサーバーから再ロードする必要があります。

    エイリアスのプロパティ​

    エイリアス属性の kind プロパティ (属性の種類) は "alias" です。

    エイリアス属性は、ターゲット属性の type プロパティを継承します。

    • ターゲット属性の kind プロパティが "storage" の場合、エイリアス属性の type はターゲット属性と同じになります。
    • ターゲット属性の kind が "relatedEntity" または "relatedEntities" の場合、エイリアスの type は 4D.Entity または 4D.EntitySelection ("classnameEntity" または "classnameSelection") になります。

    リレーションに基づくエイリアス属性は、そのターゲット属性のパスを格納する専用の path プロパティを持ちます。 同じデータクラスの属性に基づくエイリアス属性は、ターゲット属性と同じプロパティを持ちます (path プロパティはありません)。

    例題​

    以下のモデルがあるとき:

    Teacher データクラスに、教師の生徒をすべて返すエイリアス属性を定義します:

    // cs.TeacherEntity クラス

    Class extends Entity

    Alias students courses.student //relatedEntities

    Student データクラスには、生徒の教師をすべて返すエイリアス属性を定義します:

    // cs.StudentEntity クラス

    Class extends Entity

    Alias teachers courses.teacher //relatedEntities

    Course データクラスには次を定義します:

    • "name" 属性を別名で参照するためのエイリアス属性
    • 教師の名前を返すエイリアス属性
    • 生徒の名前を返すエイリアス属性
    // cs.CourseEntity クラス

    Class extends Entity

    Exposed Alias courseName name //scalar
    Exposed Alias teacherName teacher.name //scalar value
    Exposed Alias studentName student.name //scalar value

    すると、以下のクエリを実行することができます:

    // "Archaeology" という名前のコースを検索
    ds.Course.query("courseName = :1";"Archaeology")

    // Smith という講師が担当するコースを検索
    ds.Course.query("teacherName = :1";"Smith")

    // "Martin" という人が助手を務めるコースを検索
    ds.Course.query("studentName = :1";"Martin")

    // M. Smith を教師として持つ学生を検索
    ds.Student.query("teachers.name = :1";"Smith")

    // M. Martin を学生として持つ教師を検索
    ds.Teacher.query("students.name = :1";"Martin")
    // このクエリではシンプルなクエリ文字列で複雑なクエリを実行していることに注目して下さい。
    // queryPlan は以下の通りです:
    // "Join on Table : Course : Teacher.ID = Course.teacherID,
    // subquery:[ Join on Table : Student : Course.studentID = Student.ID,
    // subquery:[ Student.name === Martin]]"

    courseName エイリアスの値は編集することができます:

    // エイリアス属性を使って、授業の名称を変更します
    $arch:=ds.Course.query("courseName = :1";"Archaeology")
    $arch.courseName:="Archaeology II"
    $arch.save() //courseName と name は "Archaeology II" に変更されます

    公開vs非公開関数​

    セキュリティ上の理由から、計算属性 と エイリアス属性 と、共有シングルトン関数 を含めたデータモデルクラス関数はリモートリクエストに対してはデフォルトでは公開されていません (つまり非公開です)。

    リモートリクエストとは以下のものを指します:

    • Open datastore によって接続されたリモートの 4Dアプリケーションが送信するリクエスト
    • REST リクエスト、Qodly ページ からのリクエストも含める

    通常の 4Dクライアント/サーバーリクエストは影響されません。 このアーキテクチャーにおいては、データモデルクラス関数は常に利用可能です。

    公開されていない関数はリモートアプリケーションで利用することができず、RESTリクエストによるオブジェクトインスタンスに対して呼び出すこともできません。 リモートアプリケーションが非公開関数をアクセスしようとすると、"-10729 (未知のメンバー機能です)" エラーが返されます。

    関数あるいは属性がリモートリクエストから呼び出されるのを許可するためには、exposed キーワードを使って明示的に宣言する必要があります。 シンタックスは次の通りです:

    // 公開関数の宣言
    exposed Function <functionName>

    // 公開されたエイリアスの宣言
    exposed Alias <attributeName> <targetPath>
    // 公開された計算属性の宣言
    exposed Function get <attributeName>
    // 共有シングルトン関数の宣言
    shared singleton Class constructor()
    exposed Function <functionName>
    注

    exposed キーワードは上記で説明されているオブジェクトでのみ使用できます。 通常のユーザークラス 関数に対して使った場合、キーワードは無視され、コンパイラーはエラーを返します。

    例題​

    公開された関数によって、DataClass クラスのプライベート関数を呼び出します:

    Class extends DataClass

    // 公開関数
    exposed Function registerNewStudent($student : Object) -> $status : Object

    var $entity : cs.StudentsEntity

    $entity:=ds.Students.new()
    $entity.fromObject($student)
    $entity.school:=This.query("name=:1"; $student.schoolName).first()
    $entity.serialNumber:=This.computeSerialNumber()
    $status:=$entity.save()

    // 非公開 (プライベート) 関数
    Function computeIDNumber()-> $id : Integer
    // 新規ID番号を算出します
    $id:=...


    呼び出し元のコードは次の通りです:

    var $remoteDS; $student; $status : Object
    var $id : Integer

    $remoteDS:=Open datastore(New object("hostname"; "127.0.0.1:8044"); "students")
    $student:=New object("firstname"; "Mary"; "lastname"; "Smith"; "schoolName"; "Math school")

    $status:=$remoteDS.Schools.registerNewStudent($student) // OK
    $id:=$remoteDS.Schools.computeIDNumber() // エラー (未知のメンバー機能です)

    onHTTPGet キーワード​

    onHTTPGet キーワードを使用することで、GET 動詞(メソッド)を使用してHTTP リクエストを通して呼び出し可能な関数を宣言することができます。 このような関数は例えば4D.OutgoingMessage クラスを使用することで、あらゆるWeb コンテンツを返すことができます。

    onHTTPGet キーワードが使用できる関数は以下の通りです:

    シンタックスは次の通りです:

    // onHTTPGet 関数を宣言する
    exposed onHttpGet Function <functionName>(params) : result
    info

    exposed キーワードも忘れずに追加する必要があります。追加しなかった場合にはエラーが生成されます。

    caution

    このタイプの呼び出しは簡単に提供されるアクションであるため、デベロッパーはこのような関数でセンシティブなアクションが行われないようにする必要があります。

    params​

    onHTTPGet キーワードを持つ関数は、引数 を受け入れます。

    HTTP GET リクエストにおいては、引数はURL 内に直接渡される必要があり、また$params キーワードを使用して宣言されている必要があります(引数はコレクション内に受け取られる必要があります)。

    IP:port/rest/<dataclass>/functionName?$params='[<params>]'

    REST サーバードキュメントの引数 を参照して下さい。

    戻り値​

    onHTTPGet キーワードを持つ関数は、サポートされる型であれば、あらゆる値を返すことが可能です(引数と同様です)。

    info

    4D.OutgoingMessage クラス型の値を返すことで、そのプロパティや関数を使用してヘッダー、本文、応答のステータスなどを設定することができます。

    例題​

    以下の関数を定義したとします:

    Class extends DataClass

    exposed onHTTPGet Function getThumbnail($name : Text; $width : Integer; $height : Integer) : 4D.OutgoingMessage

    var $file := File("/RESOURCES/Images/"+$name+".jpg")
    var $image; $thumbnail : Picture
    var $response := 4D.OutgoingMessage.new()

    READ PICTURE FILE($file.platformPath; $image)
    CREATE THUMBNAIL($image; $thumbnail; $width; $height; Scaled to fit)
    $response.setBody($thumbnail)
    $response.setHeader("Content-Type"; "image/jpeg")
    return $response

    以下のHTTP GET リクエストを使用してこの関数を呼び出すことができます:

    IP:port/rest/Products/getThumbnail?$params='["Yellow Pack",200,200]'