トリガ

4D - Documentation   French   English   German   Spanish   日本語   4D v11 SQLコマンドテーマリスト   4D v11 SQLインデックス   4D v11 SQL定数テーマリスト   戻る   前   次

version 11.2 (Modified)


トリガはテーブルに付属するメソッドであり、テーブルのプロパティです。トリガを呼び出す必要はありません。テーブルレコード (追加、削除、修正) を操作するたびに4Dのデータベースエンジンによって自動的に呼び出されます。まず、簡単なトリガを記述し、その後により洗練されたものにすることができます。

トリガを使用すれば、データベースのレコードに対して"不正な" 操作が行われるのを防ぐことができます。偶発的なデータの紛失や改ざんを防ぎ、テーブル上での操作を制限することのできる非常に強力なツールです。例えば請求書システムにおいては、請求書の送付先である顧客を指定せずに誰かが請求書を追加するのを防止することができます。

トリガのアクティブ化と作成


デフォルトでは、デザインモードでテーブルを作成したときには、テーブルにはトリガはありません。

テーブルのトリガを使用するには、以下を実行する必要があります。

・トリガをアクティブにし、4Dに対してトリガをいつ起動すべきかを知らせる。

・トリガ用のコードを記述する。

まだ記述されていないトリガをアクティブにする、あるいはトリガをアクティブにしないで記述しても、テーブルに対して実行される操作に影響を与えることはありません。

1. トリガをアクティブにする

テーブルのトリガをアクティブにするには、ストラクチャのインスペクタウィンドウでテーブルのトリガ オプション (データベースイベント) のいずれかを選択しなければなりません。

新規レコード保存時:

このオプションを選択すると、レコードがテーブルに追加されるたびに、トリガが起動します。

以下の場合にトリガが起動します。

・データ入力時にレコードを追加する(デザインモード、ADD RECORD コマンド または SQLのINSERT コマンドを使用して) 。

CREATE RECORDSAVE RECORD を使用してレコードを作成し、保存する。トリガは、SAVE RECORD を呼び出したときに起動します。レコードを作成したときではありません。

・レコードを読み込む (デザインモード、または読み込みコマンドを使用して) 。

・新規レコードを作成または保存するコマンドを使用する (ARRAY TO SELECTIONSAVE RELATED ONEなど) 。

CREATE RECORD コマンドと SAVE RECORD コマンドを呼び出すプラグインを使用する。

既存レコード保存時:

このオプションを選択すると、テーブルのレコードが修正されるたびに、トリガが起動します。

以下の場合にトリガが起動します。

・データ入力時にレコードを修正する (デザインモード、MODIFY RECORD コマンド またはSQL UPDATE コマンドを使用して) 。

SAVE RECORDを使用して既存レコードを保存する。

・既存レコードを保存するコマンドを使用する (ARRAY TO SELECTIONAPPLY TO SELECTIONなど) 。

SAVE RECORD コマンドを呼び出すプラグインを使用する。

レコード削除時:

このオプションを選択すると、テーブルのレコードが削除されるたびに、トリガが起動します。

以下の場合にトリガが起動します。

・レコードを削除する (デザインモード、DELETE RECORD コマンド、DELETE SELECTION コマンドまたはSQL DELETE コマンドを使用する) 。

・リレートの削除制御オプションによって、リレート先レコードの削除を引き起こす何らかの操作を実行する。

DELETE RECORD コマンドを呼び出すプラグインを使用する。

Note: TRUNCATE TABLE コマンドはトリガを呼び出しません。

2. トリガを作成する

テーブルのトリガを作成するには、エクスプローラウィンドウを使用するか、ストラクチャのインスペクタウィンドウにある編集... ボタンをクリックするか、Alt (Windowsの場合) または Option (Macintoshの場合) キーを押して、ストラクチャウインドウのテーブルタイトルをダブルクリックしてください。詳細については、4D Design Referenceを参照してください。

データベースイベント


トリガは、前述の3つのデータベースイベントのいずれかに対して起動することができます。トリガ内で Database event関数を呼び出すことによって、どのイベントが発生しているかを検出します。この関数はデータベースイベントを示す数値を返します。

一般的には、Database eventによって返される結果に関して、 Case of ストラクチャを用いて、トリガを記述します。

      `トリガ用の [anyTable] ーブル
   C_LONGINT($0)
   $0:=0   `データベースリクエストが許可されると仮定する
   Case of
      : (Database event=On Saving New Record Event)
         `新規に作成されたレコードの保存のために適切な動作 (アクション) を実行する
      : (Database event=On Saving Existing Record Event)
         `既存のレコードの保存のために適切な動作を実行する
      : (Database event=On Deleting Record Event)
         `レコードの削除のために適切な動作を実行する
   End case

トリガと関数


トリガには、2つの目的があります。

・レコードが保存、削除される前に、レコードに対して動作 (アクション) を実行する。

・データベース操作を許可または拒絶する。

1. 動作を実行する

[Documents] テーブルにレコードが保存 (追加または修正) されるたびに、作成時を示すタイムスタンプと最新の修正時を示すタイムスタンプでレコードを "マーク" したいとします。この場合、以下のようなトリガを記述できます。

      `トリガ用の [Documents] ーブル
   Case of 
      : (Database event=On Saving New Record Event)
         [Documents]Creation Stamp:=Time stamp 
         [Documents]Modification Stamp:=Time stamp 
      : (Database event=On Saving Existing Record Event)
         [Documents]Modification Stamp:=Time stamp 
   End case 

Note: この例題で使用している Time stamp 関数は、固定日付が任意に選択された時点から経過数秒を返す小さなプロジェクトメソッドです。

いったんこのトリガを記述し、アクティブにすると、ユーザがどのような方法で [Documents] テーブルにレコードを追加または修正しても (データ入力、読み込み、プロジェクトメソッド、4Dプラグイン) 、レコードが最終的にディスクに書き込まれる前に、トリガによって、[Documents]Creation Stamp フィールドと [Documents]Modification Stamp フィールドに自動的に日付が割り当てられます。

Note: この例の詳細については、 GET DOCUMENT PROPERTIES コマンドの例を参照してください。

2. データベース操作を許可または拒絶する

データベース操作を許可または拒絶するには、トリガは、戻り値 $0トリガエラーコードを返さなければなりません。

例題

[Employees] テーブルの場合を取り上げてみましょう。データ入力時に、[Employees]Social Security number フィールドで規則を強制します。確認ボタンをクリックする際に、ボタンのオブジェクトメソッドを使用してそのフィールドをチェックします。

      ` bAcceptボタンのオブジェクトメソッド
   If (Good SS number ([Employees]SS number))
      ACCEPT
   Else
      BEEP
      ALERT ("Enter a Social Security number then click OK again.")
   End if

フィールド値が有効な場合、データ入力を受け入れます。フィールド値が無効な場合、警告を表示して、データ入力の状態になります。

[Employees] レコードをプログラムで作成した場合、以下のコードはプログラムとしては正当ですが、前述のオブジェクトメソッドで強制した規則に違反します。

      `プロジェクトメソッドから抽出する
      ` ...
   CREATE RECORD ([Employees])
   [Employees]Name :="DOE"
   SAVE RECORD ([Employees]) `  DB規則の違反!  保険証番号は保存されない!
      ` ...

[Employees] テーブルのトリガを使用して、データベースのすべてのレベルで[Employees]SS number の規則を強制することができます。トリガは以下のようになります。

      `[Employees] のトリガ
   $0:=0
   $dbEvent:=Database event
   Case of
      : (($dbEvent=On Saving New Record Event) | ($dbEvent=On Saving Existing Record Event))
      If (Not(Good SS number ([Employees]SS number)))
         $0:=-15050
      Else
         ` ...
      End if
         ` ...
   End case

いったんこのトリガを記述し、アクティブにすると、SAVE RECORD ([Employees]) 行は、データベースエンジンエラー-15050を生成し、そのレコードは保存されません。

同様に、4Dプラグインが、無効な保険証番号で[Employees] レコードを保存しようとすると、トリガは同じエラーを生成し、レコードは保存されません。

トリガを使用すれば、誰も (ユーザ、データベース設計者、プラグイン、4Dサーバを持つ4Dオープンクライアント) 保険証番号の規則を故意にまたは偶発的に違反できないことが保証されます。

テーブルのトリガが無くても、レコードを保存または削除しようとしているときに、データベースエンジンエラーが生じる場合があるので注意してください。例えば、重複不可属性を持つインデックスフィールドで重複する値を持つレコードを保存しようとすると、エラー-9998が返されます。

したがって、エラーを返すトリガは、新しいデータベースエンジンエラーをアプリケーションへ追加します。

・4Dは "通常" エラー、すなわち重複不可のインデックス、リレーショナルデータのコントロールなどを管理します。

・トリガを使用して、開発者はアプリケーションに固有のカスタムエラーを管理できます。

重要: エラーコード値は任意のものを返すことができます。ただし、4Dデータベースエンジンによって既に確保されているエラーコードは使用できません。-32000 から -15000 の間のエラーコードを使用することを強く勧めます。 -15000を超えるエラーコードは、データベースエンジン用に予約されています。

プロセスレベルでは、データベースエンジンエラーと同じ方法で、トリガエラーを処理します。

・4Dに標準のエラーダイアログボックスを表示させ、その後メソッドが停止します。

ON ERR CALL でインストールしたエラー処理メソッドを使用して、適切な方法でエラーから回復します。

Notes:

・データ入力時に、レコードを受け入れまたは削除しようとしているときにトリガエラーが返されると、エラーは重複不可なインデックスエラーのように処理されます。エラーダイアログが表示され、データ入力状態になります。デザインモード (アプリケーションモードでなく) でデータベースを使用する場合でも、トリガを使用することのメリットが得られます。

・レコードのセレクションで動作しているコマンドのフレームワーク内のトリガによってエラーが生成されると (DELETE SELECTIONのような) 、コマンドの実行は即座に停止し、セレクションは必ずしも完全に処理されません。この場合は、デベロッパによる適切な処理が必要となります。例えば、セレクションを一時的に保存したり、トリガの実行前にエラーを取り除くなどの処理が必要です。

トリガがエラーを返さないからといって ($0:=0) 、データベース操作が成功したという意味ではありません。重複不可なインデックス違反が生じる場合があります。操作がレコードの更新である場合、レコードがロックされたり、 I/O エラーが生じることがあります。トリガの実行後にチェックが終了します。ただし、プロセスを実行する高レベルにおいては、データベースエンジンまたはトリガによって返されるエラーは同じものです。トリガエラーはデータベースエンジンエラーです。

トリガと4Dアーキテクチャ


トリガはデータベースエンジンレベルで実行されます。以下の図にその様子をまとめています。

データベースエンジンが実際に配置されているマシンでトリガは実行されます。これはシングルユーザ版の4Dでは明白です。4D Serverではクライアントマシンではなく、サーバマシン (トリガを起動させるプロセスの "対の" プロセスで) 上で動作しているプロセス内でトリガは実行されます。

トリガが起動される場合、トリガはデータベース操作を実行しようとするプロセスのコンテキスト内で実行されます。トリガの実行を引き起こすこのプロセスは起動プロセスと呼ばれます。

コンテキストに含まれるエレメントは、データベースが4Dのローカルモードで実行されたか、または4D Serverで実行されたかにより異なります。

・4Dのローカルモードでは、トリガは起動プロセスのカレントセレクション、カレントレコードテーブルの読み/書き状態、およびレコードロック操作を用いて動作します。

・4D Serverでは、起動クライアントプロセスのデータベースのコンテキストのみが保持されます (ロックされたレコード、読み/書き状態など) 。また4D Serverはトリガのテーブルのカレントレコードが正確に配置されていることが保証されます。コンテキストの他のエレメント (例えばカレントセレクション) はトリガプロセスのものです。

4D環境の他のデータベースオブジェクトや言語オブジェクトは注意して使用してください。これは、トリガが起動プロセスのマシンとは別のマシン上で実行される可能性があるためです。4D Serverがこれに当てはまります。

インタープロセス変数: トリガは、トリガが実行されるマシンのインタープロセス変数へアクセスします。4D Serverでは、トリガは起動プロセスのマシンとは別のマシンへアクセスすることがあります。

プロセス変数: それぞれのトリガはプロセス変数に対して独自のテーブルを保持します。トリガは起動プロセスのプロセス変数へアクセスしません。

ローカル変数: トリガ内でローカル変数を使用できます。その有効範囲は、トリガの実行中です。ローカル変数はトリガの実行のたびに作成され、削除されます。

セマフォ: トリガ、(トリガが実行されるマシン上の) ローカルセマフォだけでなく、グローバルセマフォもテスト、または設定できます。ただしトリガは即座に実行されなければならないため、トリガ内からセマフォをテストまたは設定する場合には、十分な注意が必要です。

セットと命名セレクション: トリガ内からセットまたは命名セレクションを使用する場合、トリガが実行されるマシン上で作業することになります。クライアント/サーバモードでは、クライアントマシン上で作成されるプロセスセットとプロセス命名セレクションは、トリガ内で可視です。

ユーザインタフェース: トリガ内でユーザインタフェースエレメントを使用してないでください (警告、メッセージ、ダイアログボックスを使用しない) 。したがって、トリガのトレースはデバッガウィンドウに限定する必要があります。クライアント/サーバでは、トリガは4D Server上で実行されることを覚えておいてください。サーバマシン上で警告メッセージを表示しても、クライアント上のユーザの助けにはなりません。起動プロセスにユーザインタフェースの処理も行わせるようにしてください。

トリガとトランザクション


トランザクションは起動プロセスレベルで処理されなければなりません。トリガレベルでトランザクションを管理してはいけません。一つのトリガを実行している間に、複数のレコード (下記の例を参照) を追加、修正、削除する必要がある場合、最初にトリガ内からIn transaction コマンド を使用して、起動プロセスが現在トランザクション内にあるかどうかテストしなければなりません。そうでない場合には、トリガがロックされたレコードに出くわす可能性があります。そのため、起動プロセスがトランザクション内に無い場合は、レコードに対する操作を開始しないでください。起動プロセスに、実行しようとしているデータベース操作はトランザクション内で実行されなければならないことを知らせるためにエラーを$0 に返すだけにしてください。そうしないと、ロックされたレコードに出くわした場合、起動プロセスにはトリガの動作をロールバックする方法がなくなります。

Note: トリガとトランザクションを統合した操作を最適化するため、4Dでは、VALIDATE TRANSACTION を実行した後、トリガは呼び出されません。これにより、トリガの実行を2度繰り返すことを防ぎます。

トリガのカスケード


以下の例のようなストラクチャがあるとします。

Note: 上記のテーブルは簡略化されています。実際には、テーブルにはここに示したよりも多くのフィールドがあります。

データベースがある請求書の削除を "許可" するとしましょう。そのような操作がトリガレベルでどのように処理されるか検討してみます (プロセスレベルで削除を実行することも可能です) 。

リレートに関するデータの整合性を維持するには、請求書の削除において、[Invoices] のトリガ内で実行される以下の動作が必要となります。

・[Customer] レコードにおいて、送り状の金額分だけ、総売上フィールドの額を減らす。

・送り状に関連したすべての [Line Items] レコードを削除する。

・これはまた、 [Line Items] トリガが、削除された明細品目に関連した [Products] レコードの売り上げ数量フィールドの数量を減らすことを意味する。

・削除された送り状に関連するすべての [Payments] レコードを削除する。

最初に、 [Invoices] のトリガは、起動プロセスがトランザクション内にある場合に限り、これらの動作を実行しなければなりません。そのため、ロックされたレコードに出くわした場合にロールバックが可能になります。

次に、 [Line Items] のトリガは、 [Invoices] のトリガとカスケードしています。明細品目の削除は [Invoices] のトリガ内から DELETE SELECTION を呼び出した結果であるため、 [Line Items] のトリガは [Invoices] のトリガの実行の "範囲内で" 実行されます。

この例題にあるすべてのテーブルは、すべてのデータベースイベント対してアクティブなトリガを持っているとします。トリガのカスケードは以下のようになります。

   ・起動プロセスが請求書を削除するため [Invoices] トリガが起動される。
      ・[Invoices] トリガが総売上フィールドを更新するため、 [Customers] トリガが起動される。
      ・[Invoices] トリガが明細品目を削除するため (繰り返し) 、[Line Items] トリガが起動される。
         ・[Line Items] トリガが売上数量フィールドを更新するため、[Products] トリガが起動される。
      ・[Invoices] トリガが支払を削除するため (繰り返し) 、[Payments] トリガが起動される。

このカスケードの関係においては、[Invoices] のトリガはレベル1で、 [Customers]、 [Line Items]、 と [Payments] のトリガはレベル2で、そして [Products] のトリガはレベル3で実行されていると言えます。

トリガ内から、 Trigger level コマンドを使用して、トリガが実行されるレベルを検出します。更に、 TRIGGER PROPERTIES コマンドを使用して、他のレベルに関する情報を入手することができます。

例えば、 [Products] レコードがプロセスレベルで削除されている場合、 [Products] のトリガは、レベル3ではなく、レベル1で実行されます。

Trigger levelTRIGGER PROPERTIES を使用すれば、動作の原因を検出できます。前述の例では、請求書がプロセスレベルで削除されています。[Customers] レコードをプロセスレベルで削除すると、 [Customers] のトリガは、その顧客に関連するすべての請求書を削除しようとします。これにより、前述の例と同じように、 [Invoices] のトリガが起動されることになりますが、起動される理由は異なります。[Invoices] トリガ内から、そのトリガがレベル1で実行されたか、レベル2で実行されたかを、検出することができます。トリガがレベル2で実行された場合には、次に、それが [Customers] レコードが削除されたためであるかどうかをチェックできます。そうであれば、総売上フィールドの更新にわずらわされる必要はありません。

トリガ内での通し (シーケンス) 番号の使用


On Saving New Record Event データベースイベントを処理する際に、テーブルのレコードに対してユニークなID番号を維持するために、 Sequence number コマンドを呼び出すことができます。

例題

      `トリガ用の [Invoices] ーブル
   Case of
      : (Database event=On Saving New Record Event)
            ` ...
         [Invoices]Invoice ID number:=Sequence number ([Invoices])
            ` ...
   End case

参照

Database event, Record number, Trigger level, TRIGGER PROPERTIES, メソッド.


4D - Documentation   French   English   German   Spanish   日本語   4D v11 SQLコマンドテーマリスト   4D v11 SQLインデックス   4D v11 SQL定数テーマリスト   戻る   前   次