3

モデル駆動開発の試験の準備をしています。特定のデータベース トリガーに遭遇しました。

CREATE TRIGGER tManager_bi
FOR Manager BEFORE INSERT AS
DECLARE VARIABLE v_company_name CHAR(30);
BEGIN
  SELECT M.company
  FROM   Manager M
  WHERE  M.nr = NEW.reports_to
  INTO  :v_company_name;

  IF (NOT(NEW.company = v_company_name))
    THEN EXCEPTION eReportsNotOwnCompany;
END 

このトリガーは、管理者が外部の管理者 (つまり、同じ会社以外の管理者) にレポートする入力を防止するように設計されています。対応する OCL 制約は次のとおりです。

context Manager
   inv: self.company = self.reports_to.company

関連するテーブルは次のようになります (簡略化):

CREATE TABLE Manager
(
  nr INTEGER NOT NULL,
  company VARCHAR(50) NOT NULL,
  reports_to INTEGER,
  PRIMARY KEY (nr),
  FOREIGN KEY (reports_to) REFERENCES Manager (nr)
); 

教科書によると、このトリガーは、新しく挿入されたマネージャーが誰にも報告しない (つまり、NEW.reports_toであるNULL) 場合にも正しく機能し、実際にテストすると、正しく機能します。

しかし、私はこれを理解していません。NEW.reports_toがの場合NULL、それは変数v_company_nameが空 (初期化されていないNULL?) になることを意味します。これは、比較NEW.company = v_company_nameが を返しfalse、例外がスローされることを意味しますよね?

ここで何が欠けていますか?

(表示されている SQL は、SQL:2003 準拠であると想定されています。MDD ツールは、Firebird を RDBMS として使用する Cathedron です。)

4

2 に答える 2

2

なので。コードの強調表示のためにこの回答を作成します。

更新と挿入の両方に応答するようにトリガーを変更することをお勧めします。

CREATE TRIGGER tManager_bi
FOR Manager BEFORE INSERT OR UPDATE AS
...

その特定の例外識別子が必要ない場合は、トリガーを手書きすることをまったく避けることもできます。

そのためにSQL Check Constraintを使用できます

alter table Manager  
    add constraint chk_ManagerNotRespondsOneself
        CHECK ( NOT EXISTS (
          SELECT * FROM Manager M
          WHERE  M.nr = reports_to
            AND  M.company = company 
        ) )

CHECK 制約に対してカスタム例外を指定することは、今では不可能に見えます... http://tracker.firebirdsql.org/browse/CORE-1852

于 2016-08-22T10:02:20.877 に答える