[Salesforce.com] オブジェクトの入力規則をApexコードの処理では無視したい。

直近でどうしようか悩んでいた話。
正直、こういうことをやる必要があるお客さんはいないと思いますけど・・・。

やりたいことは以下ののようなこと。

[要望]
取引先のレコードで特定の項目が設定されていた場合、システム管理者以外のユーザが当該レコードを更新しようとすると更新できなくするという入力規則が設定されています。しかし、別の画面(VisualForce)にて取引先のデータを更新する場合には、ユーザのアクセス権およびプロファイルに関係なく取引先レコードを更新させたい。


[問題]
この場合に問題は2つあります。

  • アクセス権に関係なく更新しなくてはならない。
  • 入力規則は無視したい。

[解決策 第1弾]
当初は以下の解決策で全て解決すると思っていました。

VisualForceからデータを更新する場合には、Apexコードにより処理します。この際に、WebServiceクラスとして定義してそいつを呼び出すことにしました(普通にApexコードでカスタムコントロールを用意しても同様のことはできると思います)。マニュアルにも書いてありますが、WebServiceクラスはシステム管理者権限のコンテキストで動作します。つまり、実行ユーザのアクセス権に関係なく処理できるはずでした。

しかし、落とし穴がありました。。。

確かにWebServiceクラスの処理はシステム管理者のアクセス権限で動作しました。しかし、プロファイルについては実行ユーザのコンテキストで動作するのです!?何でよ?と思いましが、そういう仕様らしいです(;´Д`)で、問題となっていた入力規則がこの「プロファイル」も含めて判断していたために、引っかかっていたのです。。。

どうすればいいのだろうか?

[解決策 第2弾]
かなり無理くりな方法ではありますが・・・

取引先オブジェクトにApexコードで実行されたかどうかを判断させるためのフラグを設定するという解決策です。こんなことのために項目を追加するなんて普通じゃ考えられませんが、入力規則が該当レコードの情報を元に判断している、そして何よりもForce.comという用意されたプラットフォーム上で物を作る以上、仕方が無いことかと。

で、どうやったかをもうちと詳細に以下にまとめておきます。
(こんな情報が意味あるとはあまり思えませんが・・・)

1. 取引先オブジェクトに「apexFlg(API参照名はapexFlg__c)」を追加。
2. 入力規則で以下の記述を追加。

IF(ISCHANGED(apexFlg__c), false, 


<元の入力規則>


)

3. 更新するApexコードで「追記」とある行を追加。

global class TEST {
WebService static Id updateAccount(Account newAccount) {
Savepoint sp = Database.setSavepoint();

try {
// レコード取得
Account[] accounts = [SELECT Id FROM Account WHERE Id =: newAccount.Id];
// フラグを更新
accounts[0].jikkokaihi_flg__c = true; // ← 追加
update accounts[0]; // ← 追加

// 本来の更新処理
accounts[0].Name = newAccount.Name;
accounts[0].Site = newAccount.Site;
accounts[0].Phone = newAccount.Phone;
accounts[0].Website = newAccount.Website;
accounts[0].apexFlg__c = false; // ← 追加
update accounts[0];

return accounts[0].Id;
} catch (Exception e) {
// ロールバック処理
Database.rollback(sp);
throw e;
}
}
}

とりあえず、これでApexコード経由でレコードを更新するときには入力規則に引っかからないようになりました。もっとやりようはあるとは思うんですけどねぇ・・・なんかダサい解決策ではあります(;´Д`)

[Salesforce.com] オブジェクトの入力規則をApexコードの処理では無視したい。

コメントを残す