Version 180 Salesforce Spring 10
Forcecom Apex Code Developers Guide
Last updated April 27 2010
Copyright 2000-2010 salesforcecom inc All rights reserved Salesforcecomldquono softwarerdquoロゴおよびTeam Edition はsalesforcecominc の登録商標ですまたAppExchangeSuccess On Demandおよび ldquoThe Business Webrdquo はsalesforcecom inc の商標で
す本ドキュメントに記載されたその他の商標は各社に所有権があります
目次
第 1 章 Forcecom Apex コードの概要7Apex とは9
Apex はどう機能しますか11
Apex開発プロセスとは11
Apex はいつ使用するのですか14
Apexの制限とは15
最新情報16
Apex クイックスタート16
Apex ドキュメント表記規則16
Apex の主要な概念について17
最初の Apex スクリプトの作成21
第 2 章 言語構造26データ型27
プリミティブデータ型27
sObject 型30
コレクション33Enum38
変換の規則について39
変数40
大文字と小文字の区別40
定数41
式41
式について41
式の演算子について42
演算子の優先度について48
sObject 式およびリスト式の拡張49
コメントの使用49
代入ステートメント50
条件 (If-Else) ステートメント51
ループ51
Do-While ループ51
While ループ52
For ループ52
SOQL および SOSL クエリ55
SOQL および SOSL クエリ結果の処理57
SOQL 集計関数の使用57
Version 180 | 目次 | i
非常に大きな SOQL クエリの処理58
1 つのレコードを返す SOQL クエリ59
外部キーおよび親子関係の SOQL クエリについて59
SOQL クエリおよび SOSL クエリでのApex 変数の使用59
SOQL ステートメントによるすべてのレコードの問い合わせ60
ロックするステートメント60
SOQL For ループのロック61
デッドロックの回避61
トランザクションの制御61
例外ステートメント62
Throw ステートメント63
Try-Catch-Finally ステートメント63
第 3 章 Apex の呼び出し64トリガ65
バルクトリガ66
トリガ構文66
トリガコンテキスト変数67
コンテキスト変数の考慮事項68
一般的なバルクトリガイディオム69
トリガの定義70
トリガと Merge ステートメント73
トリガと復元レコード73
トリガと実行の順序74
トリガを開始しない操作75
トリガで更新できない項目76
トリガの例外77
Apex スケジューラ77
匿名ブロック81
AJAX での Apex82
第 4 章 クラスオブジェクトおよびインターフェース84クラスを理解する85
Apex クラスの定義85
拡張クラス例86
クラス変数の宣言89
クラスメソッドの定義89
コンストラクタの使用90
アクセス修飾子92
静的およびインスタンス93
Apex プロパティ95
インターフェースおよび拡張クラス97
Version 180 | 目次 | ii
パラメータ化された型とインターフェース99
カスタムイテレータ101
キーワード102
final キーワードの使用102
instanceof キーワードの使用103
super キーワードの使用103
this キーワードの使用104
transient キーワードの使用104
with sharing または without sharing キーワードの使用105
アノテーション107Future107IsTest109Deprecated109
クラスとキャスト110
クラスとコレクション111
コレクションキャスト111
Apex クラスと Java クラスの違い112
クラス定義作成113
名前付け規則114
名前のシャドウイング115
クラスセキュリティ115
名前空間プレフィックス116
メソッドの起動での名前空間の使用116
名前空間クラス変数名の優先度116
型の解決と型のシステム名前空間117
バージョン設定118
クラスおよびトリガの Salesforcecom API バージョン設定118
Apex クラスおよびトリガのパッケージバージョンの設定119
第 5 章 Apex デザインパターン120トリガと一括要求120
第 6 章 Apex のテスト122Apex のテストについて123
Apex テストの理由123
Apex のテストの対象123
Apex のユニットテスト124
runAs メソッドの使用124
LimitsstartTestおよび stopTest の使用126
SOSL クエリのユニットテストへの追加126
ユニットテストメソッドの実行127
ベストプラクティスのテスト128
Version 180 | 目次 | iii
テストの例129
第 7 章 ダイナミック Apex134Apex 定義情報について135
動的 SOQL140
動的 SOSL141
ダイナミック DML142
第 8 章 Apex の一括処理145Apex の一括処理の使用146
Apex による共有管理について153
共有の理解153
Apex を使用したレコードの共有156
Apex による共有管理の再適用160
第 9 章 管理パッケージでの Apex の開発165パッケージバージョン166
Apex の廃止166
パッケージバージョンの動作167
Apex コードの動作のバージョニング167
バージョニングされていない Apex コードの項目168
パッケージバージョンの動作のテスト169
第 10 章 Apex メソッドの Web サービスとしての公開170WebService メソッド171
WebService メソッドによるデータの公開171
WebService キーワード使用に関する考慮事項171
Web サービスメソッドのオーバーロード172
第 11 章 Apex を使用したコールアウトの呼び出し173リモート サイト設定の追加174
SOAP サービス WSDL ドキュメントからのクラスの定義174
外部サービスの呼び出し175
HTTP ヘッダーのサポート175
サポートされた WSDL 機能176
生成されるコードについて178
WSDL 使用についての考慮事項180
HTTP コールアウトの呼び出し181
証明書の使用181
証明書の生成182
SOAP サービスでの証明書の使用183
HTTP 要求での証明書の使用183
コールアウトの制限184
Version 180 | 目次 | iv
第 12 章 参照185Apex のデータ操作言語 (DML) 操作186
ConvertLead 操作187
Delete 操作191
Insert 操作192
Merge ステートメント195
Undelete 操作195
Update 操作198
Upsert操作200
DML 操作をサポートしない sObjects204
DML 操作内で一緒に使用できない sObject204
大量DML例外処理205
Apex 標準クラスおよび標準メソッド205
Primitives メソッド206
Apex Collection メソッド227
Enum メソッド237
sObject メソッド238
System メソッド259
例外メソッドの使用297
Apex クラス300
Apex電子メールクラス300
例外クラス315
Visualforce クラス317
パターンおよびマッチャークラス336
HTTP (RESTful)サービスクラス349
Apex 承認プロセスクラス361
XmlStreamクラス366
営業時間クラス373
Apex コミュニティクラス374
サイトクラス378
第 13 章 Apexスクリプトの展開382Forcecom IDE を使用した Apex の展開383
Forcecom Migration Tool の使用383
deploy について385
retrieveCode について386
runTests() について388
Forcecom Migration Tool 追加ディプロイメソッド388
付録389
Version 180 | 目次 | v
付録 A納入先請求書の例389納入先請求書の例ウォークスルー389
納入先請求書の例コード391
付録 B 予約キーワード397
付録 C Apex 開発および Visualforce 開発のセキュリティのヒント399クロスサイトスクリプト (XSS)399
Visualforce ページのエスケープされない出力と式401
クロスサイトリクエストフォージェリ (CSRF)403
SOQL インジェクション404
データアクセスコントロール405
付録 D Forcecom Web サービス API コールおよび Apex の SOAP ヘッダ406compileAndTest()407compileClasses()410compileTriggers()411executeanonymous()412runTests()413DebuggingHeader418PackageVersionHeader420
用語集421
索引435
Version 180 | 目次 | vi
第 1 章
Forcecom Apex コードの概要
過去数年間を通じてsalesforcecomは企業アプリケーションを伝統的なクライアントサーバベースからオンデマンドマルチテナントのウェ
トピック
bull Apex とは ブ環境へと移すことによってビジネスを行う方法を変えてきましたbull 最新情報 この環境Forcecom プラットフォームは営業支援 (SFA) およびサー
ビス サポートなどのアプリケーションの実行とカスタマイズをそしbull Apex クイックスタートて特定のビジネスニーズをベースにした新しいカスタムアプリケーションの構築を可能にしました
新規項目オブジェクトワークフローおよび承認プロセスを定義する機能など多くのカスタマイズオプションはSalesforcecomユーザインターフェースを通して利用可能ですまた開発者はクライアントサイドのプログラムから delete()update()または upsert()などのデータ操作コマンドを発行する Forcecom Web Services API を利用することができます
一般的にJavaJavaScriptまたはNETで書かれているこれらのクライアントサイドプログラムによって組織はより柔軟なカスタマイズが可能になりますしかしながらこれらのクライアントサイドプログラムの管理ロジックはForcecom プラットフォームサーバ上にはないため以下のような制限を受けます
bull 一般的なトランザクションを完了させるために salesforcecom サイトへの複数回の呼び出しを必要とするパフォーマンスコスト
bull API 要求におけるトランザクションコントロールの欠如bull Java または Net などのサーバコードをセキュアかつ安定してホスティ
ングすることのコストと複雑さ
これらの問題に対処し開発者がオンデマンドアプリケーションを作成する方法に革新を起こすためにsalesforcecomは現在商用のアプリケーションの次世代を構築することに関心を持った開発者用の最初のマルチテナントオンデマンドプログラム言語Forcecom Apexを導入します
bull Apex とは Apex をいつ使用するのか開発プロセス制限事項bull Apex の本リリースの新機能bull Apex クイックスタート コードを詳細に調査し最初のApex スクリ
プトを作成
より高度な開発者については「Apexデザインパターン (ページ 120)」を参照してください
Forcecom Apex コードの概要 Version 180 | | 8
Apex とは
Forcecom Apex コードは開発者が Forcecom プラットフォームサーバでフローとトランザクションの制御文をForcecom API と組み合わせて実行できるようにした強く定型化されたオブジェクト指向のプログラミング言語ですJava に似た構文を使いデータベースのストアドプロシージャのように動作する Apex コードを使用して開発者はボタンクリック関連レコードの更新およびVisualforceページなどのほとんどのシステムイベントに対しビジネスロジックを追加できますApex スクリプトはWeb サービス要求からおよびオブジェクトのトリガから開始できます
図 1 ほとんどのシステムイベントに Apex を追加できます
言語としてApex は次の特徴があります
統合Apex では次のような Forcecom プラットフォームの共通な慣用句を使用できます
bull INSERTUPDATEおよび DELETEなど組み込み DmlException処理を含むデータ操作言語 (DML)コール
bull sObject レコードのリストを返すインラインSalesforcecomオブジェクトクエリ言語 (SOQL) とSalesforcecomオブジェクト検索言語 (SOSL) のクエリ
bull 複数のレコードの一括処理を可能にするループ
Forcecom Apex コードの概要 Version 180 | Apex とは | 9
bull レコード更新の競合を回避するロック構文bull 保存された Apex メソッドから構築できるカスタム公開 Forcecom API コールbull Apexが参照するカスタムオブジェクトまたはカスタムフィールドを編集または削除しようとした場合に
発行される警告およびエラー
使いやすいApex は変数や式構文ブロックおよび条件ステートメント構文ループ構文オブジェクトおよび配列の通史参照によるパスなどよく知られた Java の用語に基づいていますApex が新しい要素を導入している場合Forcecom プラットフォームを理解しやすくまた使いやすくする構文および動作を使用しますその結果Apex は簡潔で記述しやすいコードを作成します
データ指向Apex は複数のクエリおよび DML ステートメントを Forcecom プラットフォームサーバー上の 1 つの作業にまとめるよう設計されています開発者はデータベースのストアドプロシージャを使用し複数のトランザクションステートメントをデータベースサーバーにまとめますほかのデータベースのストアドプロシージャと同様にApex はユーザインターフェースでの要素の実行はサポートしていません
厳密性Apex はオブジェクト名や項目名などスキーマオブジェクトを直接参照する強力に型付けされた言語です参照が無効である場合はコンパイル時にすぐエラーが発生しますアクティブな Apex スクリプトが要求している場合に削除されないようメタデータのすべてのカスタム項目オブジェクトクラス依存を保存します
ホステッドApex はすべて Forcecom プラットフォーム上で解釈実行制御されます
マルチテナント型ほかの Forcecom プラットフォームと同様Apex はマルチテナント環境で実行しますそのためApex ランタイムエンジンはRunaway スクリプトに対して保護するよう設計され共有リソースを独占しないようにしますこうした制限事項に違反するスクリプトは失敗しわかりやすいエラーメッセージが表示されます
自動アップグレードApexはForcecomプラットフォームのほかの部分がアップグレードされた場合にも書き直す必要がありませんコンパイルされたコードはプラットフォームのメタデータとして保存されているためシステムの残りの部分で自動的にアップグレードされます
テストしやすいApex ではコードがどれだけカバーされているかコードのどの部分がより効果的かを示すテスト結果などユニットテストを作成および実行できますSalesforcecom ではプラットフォームのアップグレードの前にメタデータに保存されたすべてのユニットテストを実行することによってスクリプトを期待どおりに動作させることができます
バージョンApex スクリプトを異なるバージョンの Forcecom API に対して保存できますこれにより動作を維持できます
Apex は Unlimited EditionDeveloper EditionEnterprise Edition に搭載されています
Forcecom Apex コードの概要 Version 180 | Apex とは | 10
Apex はどう機能しますか
すべてのApexは以下のアーキテクチャダイアグラムで示すようにForcecomプラットフォームにて全体的にオンデマンドで実行されます
図 2 ApexコードはForcecom プラットフォーム上で全体的にコンパイルされ記憶され実行されます
プラットフォームにApexスクリプトを開発者が作成して保存する時プラットフォームのアプリケーションサーバは最初にコードをApexランタイムインタプリタによって理解可能な命令の抽象セットにコンパイルしそれからメタデータとしてそれらの命令を保存します
Apex の実行はエンドユーザがおそらくボタンをクリックするかまたは Visualforce ページにアクセスすることによって行われますその際プラットフォームのアプリケーションサーバがコンパイルされた命令をメタデータから取得しランタイムインタプリタを通して結果を返します標準プラットフォームとの実行時間の違いはないためエンドユーザが気づくことはありません
Apex開発プロセスとは
Apexスクリプトの開発を始める前にsalesforcecomが推奨する以下の開発プロセスを理解する必要があります
1 Developer Edition アカウントの取得2 Apex スクリプトの作成3 Apex を作成する場合テストを作成する必要もあります4 任意でApex スクリプトを sandbox 組織にディプロイし最終ユニットテストを行います5 Salesforcecom 運用組織に Apex スクリプトを展開します
作成およびテストが完了したスクリプトはForcecom AppExchange App package に追加することも可能です
Developer Edition アカウントの取得
Apexを実行可能な3つのタイプの組織が以下のようにあります
bull 開発者組織 Developer Edition アカウントで作成された組織bull 運用組織 実際の運用データとそれらにアクセスするユーザを持っている組織
Forcecom Apex コードの概要 Version 180 | Apex はどう機能しますか | 11
bull Sandbox 組織 本番システム上に作成された運用組織のコピー
メモ Salesforcecom のTrial EditionではApexトリガが利用可能ですが他のエディションにコンバートしている時は無効です新しくサインアップした組織が Apex を含む場合ディプロイメントメソッドの1つを使ってコードを組織にディプロイする必要があります
Salesforcecom 運用組織では Apex を開発することはできません実際にユーザが利用中のシステムで開発を行う場合データまたはアプリケーションを不安定にまたは破壊することがありますsalesforcecom はsandboxまたはDeveloper Edition 組織上ですべての開発作業を行うことを推奨します
まだ開発者コミュニティのメンバーでない場合httpdeveloperforcecomjoin にアクセスしDeveloper Editionアカウントのサインアップの指示に従ってくださいDeveloper Editionアカウントによって自由にDeveloperEdition組織にアクセス可能になりますEnterprise または Unlimited Edition 組織およびApexを作成するためのsandbox 組織を既にお持ちでも開発者コミュニティのリソースを参照することを強くお勧めします
メモ Salesforcecom の運用組織ではSalesforcecom ユーザーインターフェースを使用して Apex に変更を行うことはできません
Apex の作成
次のような編集環境で Apex スクリプトおよびテストを作成できます
bull Forcecom IDE
Forcecom IDE は Eclipse IDE のプラグインですForcecom IDE にはForcecom アプリケーションを構築および展開する統合インターフェースがあります開発者および開発チーム向けに設計された IDE にはソースコードエディタテスト実行ツールウィザードおよび統合ヘルプなどForcecom アプリケーション開発を促進するツールが用意されていますForcecom IDEはhttpwikiapexdevnetcomindexphpForcecom_IDEで入手できます基本的なカラー表示エディタアウトラインビュー統合されたユニットテストおよび保存時の自動コンパイルとエラーメッセージ表示を提供しますインストール方法および使用方法の詳細はWeb サイトを参照してください
bull Salesforcecom ユーザインターフェースすべてのスクリプトは保存時にコンパイルされ構文エラーにはフラグが表示されますエラーがなくなるまでコードを保存することはできませんSalesforcecom ユーザーインターフェースはスクリプトの行番号を表示しカラー表示によるコメントキーワードリテラル文字列などさまざまな要素を区別しやすいように表示します
- 標準オブジェクトのトリガの場合は [設定] [カスタマイズ]をクリックしオブジェクト名をクリックしてから [トリガ] をクリックしますトリガの詳細ページで[新規] をクリックしBodyテキストボックスにコードを入力します
- カスタムオブジェクトのトリガ場合は[設定] [開発] [オブジェクト] をクリックしオブジェクトの名前をクリックしますトリガの関連リストで[新規]をクリックしBodyテキストボックスにコードを入力します
- クラスの場合[設定] [開発] [Apex クラス] をクリックします[新規] をクリックしBodyテキストボックスにコードを入力します
メモ Salesforcecom の運用組織ではSalesforcecom ユーザーインターフェースを使用して Apex に変更を行うことはできません
bull メモ帳などのテキストエディタApexスクリプトを作成した後アプリケーションにコピーして貼り付けたりAPI コールのいずれかを使用してディプロイすることができます
Forcecom Apex コードの概要 Version 180 | Apex開発プロセスとは | 12
ヒント Eclipse プラグインを拡張または Apex IDEを独自に開発することも可能ですWebサービス APIにはトリガやクラスをコンパイルテストメソッドを実行するための方法が提供されまた MetadataAPI には本番環境にコードをディプロイするための方法が提供されています詳細はApex スクリプトのディプロイ (ページ 382)およびApex の Web サービス API コールと SOAP ヘッダー (ページ 406)
テストの作成
テストは長期間の開発を正常に行うためにキーとなるもので開発プロセスの重要な部分を占めますテストベースの開発プロセスつまりコード開発と同じ回数行うテスト開発を使用することを強くお勧めします
強固な開発を促進するためにエラーのないコードApex はユニットテストの作成および実行をサポートしますユニットテストは特定のコードが適切に動作しているかを確認するクラスメソッドですユニットテストは引数をとらずデータをデータベースにコミットせず電子メールを送信せずメソッド定義で testMethod
キーワードを使用してフラグを立てます
またForcecom AppExchange 向けに Apex を展開またはパッケージ化する前に次の点を実行する必要があります
bull Apex スクリプトの75がユニットテストの適用範囲でかつすべてのテストは正しく完了します
次の点に注意してください
- 運用組織に展開する場合組織の名前空間内の各ユニットテストが行われます- Systemdebugへのコールはユニットテストの Apex コードの範囲の一部としてカウントされません- Apex コードの 75 だけをテストでカバーする必要がある場合フォーカスはカバーされるコードの割合
にあってはいけません代わりに正のケースや負のケース大量のレコードや単一レコードなどアプリケーションのすべての使用ケースがカバーされていることを確認してくださいコードの 75 以上がユニットテストにカバーされます
bull すべてのトリガについていくつかのテスト適用範囲ありますbull すべてのクラスとトリガは正常にコンパイルされます
テスト作成の詳細は「Apex のテスト (ページ 122)」を参照してください
Sandbox 組織への Apex のディプロイ
Salesforcecomはテストやトレーニングなど様々な目的のために運用組織のデータとアプリケーションに影響を与える事なく運用組織のコピーを複数作成可能にしますこれらのコピーは Sandbox と呼ばれSalesforcecomの運用組織とほぼ同じですSandbox はSalesforcecom 運用組織から完全に独立しているためSandbox で実行する操作は Salesforcecom 運用組織に影響せず逆に運用組織で実行する操作が Sandbox に影響することもありません
Apex を Forcecom IDE から Salesforcecom 組織に展開するにはForcecom コンポーネント展開ウィザードを使用しますForcecom IDE に関する詳細はhttpwikiapexdevnetcomindexphpForcecom_IDE を参照してください
deploy() Metadata API コールを使用して開発者組織から Sandbox 組織に Apex を展開することもできます
もう1つの便利なAPIコールはrunTests()です開発またはsandbox組織においては特定のクラスクラスのリストまたは名前空間のためにユニットテストを実行可能です
Salesforcecom には簡単にこれらのコマンドをコンソール内で発行可能にする Forcecom Migration Tool もありますまたは自身のディプロイコードを実行することも可能です
Forcecom Apex コードの概要 Version 180 | Apex開発プロセスとは | 13
詳細については「Forcecom 移行ツールの使用」 (ページ 383)と「Apex スクリプトのディプロイ」 (ページ 382)を参照してください
Apex の Salesforcecom 運用組織へのディプロイ
すべてのユニットテストを完了させApex スクリプトが適切に実行されることを確認した後で最終ステップはSalesforce 運用組織に Apex に展開することになります
Apex を Forcecom IDE から Salesforcecom 組織に展開するにはForcecom コンポーネント展開ウィザードを使用しますForcecom IDE に関する詳細はhttpwikiapexdevnetcomindexphpForcecom_IDE を参照してください
Salesforce 運用組織に Apex を展開するにはcompileAndTest API コールも使用可能です
詳細は「Apex のディプロイ」 (ページ 382)を参照してください
Apex スクリプトの Forcecom AppExchange App アプリケーションへの追加
AppExchange 用に作成するアプリケーションに Apex スクリプトを含めることができます
パッケージの一部として含まれている Apex はどれも累積的テストカバー率が最低でも 75 である必要があります各トリガも何らかのテストを行なう必要がありますパッケージを AppExchange にアップロードする時すべてのテストが実行されエラーなく実行されることが確認されますまたパッケージがインストールされる時にもすべてのテストがインストール先の組織で実行されますインストールを実行する管理者はいずれかのテストに失敗した場合パッケージのインストールを続行するかどうかを判断できます
またsalesforcecom はApex を含む AppExchange パッケージは管理パッケージとするよう推奨します
詳細はSalesforcecomオンラインヘルプの「管理パッケージとは 」を参照してください管理パッケージのApexの詳細は「管理パッケージでの Apex の開発 (ページ 165)」を参照してください
メモ 翻訳文のあるカスタムラベルへの参照を含む Apex クラスのパッケージに翻訳を含めるにはトランスレーションワークベンチを有効にし翻訳されたカスタムラベルで使われている個々の言語を明示的にパッケージに含めてください詳細はオンラインヘルプの項目「カスタムラベルの概要」を参照してください
Apex はいつ使用するのですか
Salesforcecomでは強力な CRM 機能を提供するアプリケーションが組み込まれていますまた組織に応じて組み込みアプリケーションをカスタマイズする機能も用意していますただし組織には既存の機能ではサポートされていない複雑なビジネスプロセスがあることがありますこの場合Forcecom プラットフォームには高度な管理者や開発者がカスタム機能を実装できるさまざまな方法が搭載されています搭載されている機能はApexVisualforceおよび Forcecom Web サービス API です
Apex
次のような場合に Apex を使用します
bull Web サービスを作成するbull 電子メールサービスを作成するbull 複数のオブジェクトに複雑な検証を実行するbull ワークフローでサポートされていない複雑なビジネスプロセスを作成する
Forcecom Apex コードの概要 Version 180 | Apex はいつ使用するのですか | 14
bull カスタムトランザクションロジック (1 つのレコードやオブジェクトだけでなくトランザクション全体で発生するロジック) を作成する
bull 操作がユーザインターフェースVisualforce ページまたは Web サービス API のどこで行われているかに関係なく操作が実行されるといつでも行われるようレコードの保存などの別の操作にカスタムロジックを添付する
Visualforce
Visualforce ではタグベースのマークアップ言語を使用して開発者はより効果的にアプリケーションを開発したりSalesforcecomのユーザインターフェースをカスタマイズしたりできますVisualforceを使用して次のことができます
bull ウィザードやその他のマルチステッププロセスの構築bull アプリケーションを介した独自のカスタムフローコントロールの作成bull 最適かつ効果的なアプリケーションの相互作用を目的としたナビゲーションパターンやデータ固有ルール
の定義
詳細については『Visualforce Developers Guide』を参照してください
Forcecom Web サービス API
度に 種類のレコードを処理しトランザクション処理(Savepointの設定またはロールバックなど)を必要としないアプリケーションの場合標準の Forcecom Webサービス API コールを使用します
詳細は『Forcecom Web Services Developers API Guide』を参照してください
Apexの制限とは
Apexは開発者のオンデマンドビジネスアプリケーションを大胆に変えましたしかし一般的なプログラム言語を意味しているわけではありませんこのリリースではApex は以下の目的で使用することができません
bull エラーメッセージ以外のユーザインターフェースのレンダリングbull 標準機能の変更 -Apex は標準機能が呼ばれるのを防ぐかまたは機能を追加することのみ可能ですbull 一時ファイルの作成bull スレッドの作成
ヒント
Apexスクリプトは他のすべての組織で使用される共有リソースであるForcecomプラットフォームで実行されます一貫したパフォーマンスと拡張性を保証するためApexの実行はApex実行がSalesforcecomのサービス全体に一切影響を及ぼさないことを保証するガバナ制限に拘束されていますこれは各Apexスクリプトは1 回のトランザクションで実行できる操作数 (DML や SOQL など) に制限があることを意味します
すべての Apex トリガ要求は1 件から 1000 件のレコードを含むコレクションを返しますコードが一度に 1 つのレコードだけに機能すると想定することはできませんそのため一括処理を行うプログラミングパターンを実装する必要がありますそうでない場合ガバナ制限に触れる場合があります
関連リンクApex デザインパターン
Forcecom Apex コードの概要 Version 180 | Apexの制限とは | 15
最新情報
Apex の新機能および変更された機能概要について Winter 10 をレビューします
Apex クイックスタート
Developer Edition を導入しApex スクリプトを作成するために使用するツールを選択するとApex の主要な概念の一部を学びたいと考えるでしょうApexは Java に非常に似ているため多くの機能がなじみ深いものです
基本を確認したら最初の Apex プログラム非常に簡単な「Hello World」スクリプトを作成しましょうスクリプトを作成した後ユニットテストを書いて拡張することも可能です
さらに納入先請求書の例を検証することもできますこの例ではより多くの言語の機能を説明しています
メモ Hello World スクリプトと納入先請求書の例ではカスタム項目およびオブジェクトが必要です項目やオブジェクトを自分で作成したりオブジェクト項目および Apex スクリプトを管理パッケージとして Forcecom AppExchange からダウンロードできます詳細はwikiapexdevnetcomindexphpDocumentation を参照してください
Apex ドキュメント表記規則Apex および Visualforce ドキュメントは次の表記規則を使用しています
説明規則
構文の記述においてmonospace フォントはかっこを除いて表示されたとおりに入力する必要のある項目を示します例Public class HelloWorld
Courier font
構文の記述においてイタリック体は変数を示します実際値を入力してください次の例では3 つの値を入力する必要があります
datatype variable_name [ = value]
Italics
構文の記述において不等号は (lt gt) そのまま入力しますltapexpageBlockTable value=accountContacts var=contactgtltapexcolumn value=contactNamegt ltapexcolumn
lt gt
value=contactMailingCitygt ltapexcolumnvalue=contactPhonegt ltapexpageBlockTablegt
シンタックスの説明では中かっこ ( ) は表示通りに入力しますltapexpagegt Hello $UserFirstNameltapexpagegt
Forcecom Apex コードの概要 Version 180 | 最新情報 | 16
説明規則
構文の記述において大かっこに囲まれているものはオプションです次の例では valueの指定はオプションです
datatype variable_name [ = value]
[ ]
構文の記述において「または」を意味します次のいずれか (すべてではない) を実行できます次の例では2 つのいずれかの方法で未投入のセットを作成するかセットを投入することができますSetltdatatypegt set_name [= new Setltdatatypegt()] | [= newSetltdatatypevalue [ value2 ] ] |
|
Apex の主要な概念について一般的なApexスクリプトにはその他のプログラミング言語でよく知られている多くのことが含まれています
図 3 Apex のプログラミング要素
ここではApex の基本機能および主要な概念の一部について説明しています
バージョン設定の使用
Salesforcecomユーザインターフェースで保存するApexクラスまたはトリガに対して Salesforcecom APIのバージョンを指定できますこの設定は使用する Forcecom Web サービス API だけではなくApex バージョンも示します保存した後バージョンを変更できます各クラス名またはトリガ名は一意でなければなりません異なるバージョンに対して同じクラスまたはトリガを保存することはできません
Forcecom Apex コードの概要 Version 180 | Apex の主要な概念について | 17
バージョン設定を使用してクラスまたはトリガをAppExchangeから組織にインストールした管理パッケージの特定のバージョンと関連付けることができます管理パッケージのこのバージョンはより新しいバージョンの管理パッケージがインストールされてもバージョン設定を手動で更新しない限りクラスまたはトリガによって引き続き使用されますインストール済み管理パッケージを設定リストに追加するには使用可能なパッケージのリストからパッケージを選択しますリストはクラスまたはトリガにまだ関連付けられていないインストール済み管理パッケージがある場合にのみ表示されます
管理パッケージでのバージョン設定の使用の詳細はSalesforcecomオンラインヘルプの「パッケージバージョンとは」を参照してください
変数メソッドおよびクラスの命名
変数メソッドまたはクラスを命名する場合Apex の予約キーワードを使用することはできませんこれらにはlisttestまたは account予約キーワードなどApex および Forcecom プラットフォームの一部である語が含まれます
変数および式の使用
Apex は強力に型付けされた言語ですつまり最初に参照するときに変数のデータ型を宣言する必要がありますApex データ型にはIntegerDateBoolean の基本のデータ型またリストマップオブジェクトおよび sObjects など高度なデータ型があります
変数は名前およびデータ型で宣言されます宣言する場合値を変数に割り当てることができますまた後で値を代入してもかまいません変数を宣言する場合次の構文を使用します
datatype variable_name [ = value]
ヒント 上記の末尾にあるセミコロンはオプションではありませんステートメントの最後には必ずセミコロンを使用します
次の例は変数の宣言を示しています
次の変数は Count という名前でデータ型は Integer 値は 0 です Integer Count = 0 次の変数名は Totalデータ型は Decimal ですNote 値は割り当てられていませんDecimal Total 次の変数は取引先で sObject として参照されますAccount MyAcct = new Account()
Forcecom Apex コードの概要 Version 180 | Apex の主要な概念について | 18
すべての非プリミティブデータ型が参照によって渡されますがすべてのプリミティブ変数は値によって渡されます
ステートメントの使用
ステートメントは操作を実行するコード化された指示です
Apex の場合ステートメントの末尾にセミコロンを使用し次の種類のいずれかとなります
bull 代入 (値を変数に割り当てるなど)bull 条件 (if-else)bull ループ
- Do-while- While- 対象
bull ロックbull データ操作言語 (DML)bull トランザクションの制御bull メソッド呼び出しbull 例外処理
ブロックは中かっこでまとめられる一連のステートメントです単一のステートメントが使用できる場所ならどこでも使用することができます例
if (true) Systemdebug(1) Systemdebug(2) else Systemdebug(3) Systemdebug(4)
ブロックが 1 つのステートメントだけで構成されている場合中かっこはなくなります例
if (true) Systemdebug(1) else Systemdebug(2)
コレクションの使用
Apex には次のようなコレクションがあります
bull リスト (配列)bull Mapbull セット
リストはIntegerStringオブジェクトその他のコレクションなど要素のコレクションです要素の順序が重要な場合にリストを使用しますリスト内に重複した要素を持つことができます
リスト内の最初の索引の位置は必ず 0 になります
リストを作成する手順は次のとおりです
bull newキーワードを使用しますbull ltgt文字で囲んだ要素の種類の前に Listキーワードを使用します
次の構文を使用してリストを作成します
List ltdatatypegt list_name [= new Listltdatatypegt()] | [=new Listltdatatypegtvalue [ value2 ]] |
Forcecom Apex コードの概要 Version 180 | Apex の主要な概念について | 19
次の例では Integer のリストを作成し変数 My_Listに割り当てますApex は強力に型付けされているためMy_Listのデータ型を Integer のリストとして宣言する必要があります
ListltIntegergt My_List = new ListltIntegergt()
詳細は「リスト」 (ページ 34)を参照してください
セットは順不同の要素のコレクションですセット内の各要素は一意である必要がありますセットにはStringIntegerDate などプリミティブデータ型のみ含まれますオブジェクトなどのより複雑なデータ型を含めることはできません
セットを作成する手順は次のとおりです
bull newキーワードを使用しますbull ltgt文字で囲んだプリミティブデータ型の前に Setキーワードを使用します
次の構文を使用してセットを作成します
Setltdatatypegt set_name [= new Setltdatatypegt()] | [= new Setltdatatypevalue [ value2 ] ] |
次の例ではString のセットを作成しますセットの値は中かっこ を使用して渡されます
SetltStringgt My_String = new SetltStringgta b c
詳細は「セット」 (ページ 35)を参照してください
マップはキー-値のペアのコレクションですキーにはプリミティブデータ型が含まれます値はプリミティブデータ型オブジェクトやその他のコレクションとなりますキーによって何か検索する場合はマップを使用しますマップ内のでは重複する値を持つことはできますが各キーは一意である必要があります
マップを作成する手順は次のとおりです
bull newキーワードを使用しますbull ltgt文字で囲みカンマで区切ったキー-値の前に Mapキーワードを使用します
次の構文を使用してマップを作成します
Mapltkey_datatype value_datatypegt map_name [=new mapltkey_datatype value_datatypegt()] |[=new mapltkey_datatype value_datatypegt key1_value =gt value1_value [ key2_value =gtvalue2_value ]] |
次の例ではキーのデータ型が Integer値が String というマップを作成しますこの例でマップが作成されると中かっこ の間にマップの値が渡されます
MapltInteger Stringgt My_Map = new MapltInteger Stringgt1 =gt a 2 =gt b 3 =gt c
詳細は「マップ」 (ページ 36)を参照してください
Forcecom Apex コードの概要 Version 180 | Apex の主要な概念について | 20
条件分岐の使用
ifステートメントはアプリケーションが条件に基づいてさまざまなことを実行できる真-偽のテストです基本構文は次のとおりです
if (Condition) 真の場合はこれを実行 else 真でない場合はこれを実行
詳細は「条件 (If-Else) ステートメント」 (ページ 51)を参照してください
ループの使用
ifステートメントを使用するとアプリケーションは条件に基づいて操作を実行できますがループはアプリケーションに条件にも続いて同じ事を繰り返し実行するよう指示しますApex は次のようなループがあります
bull Do-whilebull Whilebull 対象
Do-while ループはコードが実行された後条件をチェックします
While ループはコードが実行される前開始時に条件をチェックします
Forループを使用するとループ内で使用される条件をより詳細に制御できますまたApexでは条件を設定する従来の For ループ条件の一部としてリストおよび SOQL クエリを使用する For ループを使用できます
詳細は「ループ」 (ページ 51)を参照してください
最初の Apex スクリプトの作成次の「Hello World」の例ではApex の基本概念の大部分について説明していますこの例ではHelloというカスタム Account 項目が新しい取引先が作成されると値としてのテキスト「World」で更新されます
メモ この例はユーザが Salesforcecom アプリケーションに慣れており標準の取引先オブジェクトにHelloというカスタムテキスト項目を定義していると想定しています詳細はSalesforcecom オンラインヘルプの「項目とリレーションの追加」を参照してください
この画像は取引先が作成された後の Account 詳細ページにある空の Hello項目を示しています
図 4 値のない Hello 項目
Forcecom Apex コードの概要 Version 180 | 最初の Apex スクリプトの作成 | 21
値「World」で自動的にこの項目を更新するには[設定」 [開発] [Apex クラス] をクリックし[新規] をクリックした後 [Body]テキストボックスに次のコードを入力します
このクラスは取引先レコードの Hello 項目を更新して クラスに渡します public class MyHelloWorld
public static void addHelloWorld(Account[] accs)
for (Account aaccs) if (aHello__c = World) aHello__c = World
入力後必ず [保存] をクリックしてください
コードの最初の行は次のようになります
public class MyHelloWorld
Apex スクリプトは通常クラスに含まれていますこのクラスでは publicと定義されているため他の Apexスクリプトから使用できます詳細は「クラスオブジェクトおよびインターフェース」 (ページ 84)を参照してください
コードの 2 番目の行からメソッド定義が始まります
public static void addHelloWorld(Account[] accs)
このメソッドは addHelloWorldと呼ばれ公開かつ静的メソッドですこれは静的メソッドであるためクラスのインスタンスを作成してメソッドにアクセスする必要はありませんこのメソッドにアクセスするにはカンマ()の前にクラス名をそしてメソッド名を指定します詳細は「静的およびインスタンス」 (ページ93)を参照してください
このメソッドでは 1 つのパラメータAccount レコードのリストを使用しますこれは変数 accsに割り当てられます
コードの次の項ではメソッド定義の残りが記述されています
for (Account aaccs) if (aHello__c = World) aHello__c = World
フィールド名の後に __cを記述しHello__cとしますここではそれがカスタム項目つまり自分で作成した項目であることを示しますSalesforcecom のデフォルトで提供されている標準項目には__cを使用せずAccountnameのように同じ種類のドット表記を使用して アクセスします
この部分のコードを実行するためにこの例ではトリガという Apex コンポーネントを使用しますトリガはForcecom プラットフォームデータベースの特定の種類のレコードが挿入更新または削除される前後で実行するコードの一部ですすべてのトリガはトリガを発生したレコードにアクセスするためのコンテキスト変数と共に実行されますすべてのトリガは一括処理(bulk)から呼ばれるため複数のレコードを一度に処理する必要があります
次のトリガは Account オブジェクトと関連しHelloWorldクラスで定義した addHelloWorldメソッドをコールしますこのトリガを組織に追加するには[設定] [カスタマイズ] [取引先] [トリガ] をクリックし[新規] をクリックして次のコードに入力しテンプレートで自動的に生成されたものを置き換えます
trigger helloWorldAccountTrigger on Account (before insert)
Account[] accs = Triggernew
Forcecom Apex コードの概要 Version 180 | 最初の Apex スクリプトの作成 | 22
MyHelloWorldaddHelloWorld(accs)
コードの最初の行はトリガを定義します
trigger helloWorldAccountTrigger on Account (before insert)
トリガに名前を指定し処理するオブジェクトを指定し発生させるイベントを定義しますたとえばこのトリガは新しい取引先レコードがデータベースに追加される前に実行します
トリガの次の行はaccsという名前の取引先レコードのリストを作成しTriggernewというトリガコンテキスト変数の内容を割り当てますTriggernewなどのトリガコンテキスト変数はすべてのトリガで暗黙的に定義されトリガを発生させるレコードへにアクセスできますこの場合Triggernewには挿入される新しい取引先がすべて含まれています
Account[] accs = Triggernew
コードの次の行はMyHelloWorldクラスのメソッド addHelloWorldをコールします新しい取引先の配列に渡します
MyHelloWorldaddHelloWorld(accs)
このコードは before insertトリガイベントで実行されるため新しいレコードを作成してコードを実行する必要があります新しいレコードを作成するには[取引先] タブをクリックして [新規]をクリックし新しい取引先をクリックします必須項目は名前だけです[保存] をクリックするとHello項目に「World」が入力されます
図 5 コード実行後Hello 項目に入力
Hello World プログラムへのテストの追加
テストとユニットテストは開発プロセスの重要な部分です
bull 少なくとも75の Apex スクリプトをユニットテストでカバーする必要がありますさらにすべてのトリガが一部のテスト範囲に含まれている必要があります
bull 100 のスクリプトを可能な場合はユニットテストでカバーすることをお勧めしますbull Systemdebugへのコールはユニットテストの Apex コードの範囲の一部としてカウントされません
次の例では前の例で使用された同じクラスおよびトリガを使用します
Forcecom Apex コードの概要 Version 180 | 最初の Apex スクリプトの作成 | 23
テストをプログラムに追加するには新しいクラスを作成する必要がありますクラスを作成するには[設定] [開発] [Apex クラス] をクリックし[新規] をクリックしますクラスの [内容] テキストボックスでその次を入力します
isTest private class HelloWorldTestClass
static testMethod void validateHelloWorld() Account a = new Account(name=T1 Account) Insert account insert a
Retrieve account a = [SELECT hello__c FROM account WHERE Id =aid]
Test that HelloWorld program correctly added the value World to the Hello fieldSystemassertEquals(World ahello__c)
入力後必ず [保存] をクリックしてください
このクラスはアノテーション isTestを使用して定義しますそのようにして定義されたクラスにはテストメソッドのみが含まれますテストメソッドを既存のクラスに追加することに対しテスト用に個別のクラスを作成することの利点はisTestで定義されたクラスはすべての Apex スクリプトの 1 MB の組織の制限に対してカウントしないという点ですisTestアノテーションを個別のメソッドに追加することもできます詳細は「IsTest」 (ページ 109) および 「実行ガバナーと制限の理解」を参照してください
メソッド validateHelloWorldは testMethodとして定義されていますつまりデータベースに変更が行われている場合実行が完了すると自動的にロールバックされます
まずテストメソッドは新しい取引先を作成しデータベースに一時的に挿入します
Account a = new Account(name=T1 Account) Insert account insert a
取引先が挿入されると挿入時に取引先に割り当てられていた ID を使用してコードは取引先を取得します
Retrieve account a = [SELECT hello__c FROM account WHERE Id =aid]
HelloWorldクラスを実行すると「World」という言葉が hello__c項目に挿入されます次の行は実際のテストでメソッド addHelloWorldが実際に実行しているかを検証し予期した結果を作成します
Test that HelloWorld program correctly added the value World to the Hello fieldSystemassertEquals(World ahello__c)
このユニットテストを実行するには[設定] [開発] [Apex クラス] をクリックしクラス名HelloWorldTestClassをクリックして[テストを実行] をクリックします
ユニットテストの実行結果ページには次のセクションがあります各セクションは展開したり折りたたんだりできます
bull テストランの回数失敗の回数ユニットテストが網羅する Apex スクリプトの割合を詳細に示す概要セクション
重要
- 少なくとも75の Apex スクリプトをユニットテストでカバーする必要がありますさらにすべてのトリガが一部のテスト範囲に含まれている必要があります
- 100 のスクリプトを可能な場合はユニットテストでカバーすることをお勧めします- Systemdebugへのコールはユニットテストの Apex コードの範囲の一部としてカウントされま
せん
Forcecom Apex コードの概要 Version 180 | 最初の Apex スクリプトの作成 | 24
bull テストの失敗回数 (発生した場合)bull コードカバー率セクション
このセクションでは組織のすべてのクラスおよびトリガおよびテストの対象となる各クラスおよびトリガのコードの行の割合を一覧表示しますカバー率の数値をクリックするとページが表示されテストの対象となるクラスまたはトリガのコードの行がすべて青でまたテストの対象外であるコードのすべての行が赤で強調表示されますまたクラスまたはトリガの特定の行がテストで実行された回数も表示されます
bull テストカバー率の警告 (発生した場合)bull デバッグログ
デバッグログは自動的に特定のログレベルとカテゴリに設定されます変更はできません
レベルCategory
INFOデータベースFINEApex コードINFOApex プロファイリングINFOワークフローINFOValidation
次は結果ページの前半の例です
図 6 HelloWorldTest 結果ページ
Forcecom Apex コードの概要 Version 180 | 最初の Apex スクリプトの作成 | 25
第 2 章
言語構造
次の言語構造はApex の基本部分を形成しますトピック
bull データ型bull データ型bull 変数bull 変数bull 式bull 式bull 代入ステートメントbull 代入ステートメントbull 条件 (If-Else) ステートメントbull 条件 (If-Else) ステートメントbull ループbull ループbull SOQL および SOSL クエリbull SOQL および SOSL クエリbull ロックするステートメント
bull ロックするステートメント bull トランザクションの制御bull トランザクションの制御 bull 例外ステートメントbull 例外ステートメント
Apex スクリプトはトリガまたはクラスのいずれかに含まれています詳細は「トリガ」 (ページ 65)および「クラスオブジェクトおよびインターフェース」 (ページ 84)を参照してください
データ型
Apex の場合すべての変数および式には次のいずれかのデータ型があります
bull IntegerDoubleLongDateDatetimeStringIDまたは Boolean (プリミティブデータ型 (ページ 27)を参照) などのプリミティブデータ型
bull AccountContactまたは MyCustomObject__c など汎用 sObject または特定 sObject としての sObject (「sObject型」 (ページ 30)を参照)
bull コレクション
- プリミティブsObjectsユーザ定義のオブジェクトApex から作成されたオブジェクトまたはコレクションのリストまたは配列 (リスト (ページ 34))
- プリミティブデータ型のセット (「セット」 (ページ 35)を参照)- プリミティブからプリミティブsObject またはコレクションへのマップ (「マップ」 (ページ 36)を参照)
bull enum など値の型が決まったリスト (see 「Enum」 (ページ 38)を参照)bull ユーザー定義のApexクラスから作成されるオブジェクト (「クラスオブジェクトおよびインターフェース」
(ページ 84)を参照)bull システムによって提供された Apex クラスから作成されるオブジェクト (「Apex クラス」 (ページ 300)を参照)bull Null (任意の変数に割り当てることができる null定数)
メソッドは上記のいずれかのデータ型を返すかまたは値を返さない Void となります
データ型チェックはコンパイル時に行われますたとえばデータ型 Integer のオブジェクト項目に String の値が割り当てられるとパーサーはエラーを生成しますただしすべてのコンパイル時の例外はエラーの行番号および列番号を記載した特定の障害コードとして返されます詳細は「Apex のデバッグ」を参照してください
プリミティブデータ型Apex はForcecom Web サービス API と同じプリミティブデータ型を使用しますすべてのプリミティブデータ型は参照ではなく値によって渡されます
Apex プリミティブデータ型には次のとおりです
説明データ型
単一のオブジェクトとして保存されるバイナリデータ型のコレクションtoString
メソッドおよび valueOfメソッドを使用してこのデータ型をそれぞれ String にBlob
または String から変換できますBlobs は Web サービス引数として受け入れられドキュメント (ドキュメントの本文は Blob) に保存され添付ファイルとして送信されます詳細は「Cryptoクラス」 (ページ 359)を参照してください
truefalsenullのみを割り当てることができる値例
Boolean isWinner = true
Boolean
言語構造 Version 180 | データ型 | 27
説明データ型
特定の日を示す値Datetime 値と異なりDate 値に時間に関する情報は含まれていませんDate は必ずシステム静的メソッドを使用して作成する必要があります
まれに Date 変数に数値を追加して日付の追加などDate 値を処理することはできませんDate メソッドを使用する必要があります
Date
タイムスタンプなど特定の日と時刻をを示す値Datetime は必ずシステム静的メソッドを使用して作成する必要があります
まれに Datetime 変数に数値を追加して分の追加などDatetime 値を処理することはできませんDatetime メソッドを使用する必要があります
Datetime
小数を示す数値Decimal は任意の精度数です通貨項目には自動的にデータ型Decimal が割り当てられます
明示的に scaleつまり小数部分の桁数を設定しない場合setScaleメソッドを使用する Decimal に対しスケールは Decimal が作成された項目によって決まります
Decimal
bull Decimal がクエリの一部として作成される場合スケールはクエリから返される項目のスケールに基づきます
bull Decimal が String から作成される場合スケールは String の小数点の後の文字数となります
bull Decimal が小数以外の数値から作成される場合スケールは数値を String に変換し小数点以下の文字数を指定して決定します
小数を含む 64 ビットの数値Doubles の最小値は -263最大値は 263-1 です例
Double d=314159
Double
Doubles 特定の表記 (e) はサポートされていません
有効な 18 文字の Forcecom レコードの識別子例
ID id=00300000003T2PGAA0
ID
IDを 15 文字の値に設定するとApex は自動的に 18 文字の表現に変換します無効な ID値はランタイム例外により却下されます
小数を含まない 32 ビットの数値Integer の最小値は -2147483648最大値は2147483647 です例
Integer i = 1
Integer
言語構造 Version 180 | プリミティブデータ型 | 28
説明データ型
小数を含まない 64 ビットの数値Doubles の最小値は -263最大値は 263-1 ですInteger で提供されたものより広い値の範囲が必要な場合このデータ型を使用します例
Long l = 2147483648L
Long
単一引用符で囲まれた文字のセット例String s = The quick brown fox jumped over the lazy dog
文字列
文字列サイズ文字列には使用できる文字数の制限はありません代わりにヒープサイズの制限を使用してApex プログラムが大きくならないようにします
空の文字列と末尾の空白文字 sObject String 項目値は Web サービス API と同じ規則に従います空白は使用できず (nullのみ)先頭および末尾に空白文字を使用できませんデータベースの保存にはこれらの変換が必要です
それに対しApexの String は nullまたは空白となりますまた先頭と末尾に空白文字を使用することができます (メッセージを構築するために使用できます)
Solution sObject 項目の SolutionNote は特別なデータ型の String として処理しますHTML Solutions を有効にした場合この項目で使用される HTML タグはオブジェクトは作成または更新される前に検証されます無効な HTML が入力されるとエラーが投げられますこの項目で使用される JavaScript はオブジェクトが作成または更新される前に削除されます次の例ではSolution が詳細ページに表示されSolutionNote 項目は H1 HTML 形式を適用します
trigger t on Solution (before insert) Triggernew[0]SolutionNote=lth1gthellolth1gt
次の例ではSolution が詳細ページに表示されSolutionNote 項目はHelloGoodbyeのみを含みます
trigger t2 on Solution (before insert) Triggernew[0]SolutionNote= ltjavascriptgtHelloltjavascriptgtGoodbye
詳細はSalesforcecomオンラインヘルプの「HTML ソリューションとは 」を参照してください
エスケープシーケンス Apex のすべての String は SOQL 文字列と同じエスケープシーケンス (b (バックスペース)t (タブ)n (改行)f (改ページ)r (改行復帰) (二重引用符) (一重引用符)および (バックスラッシュ)) を使用します
比較演算子 Java と異なりApex の Strings では比較演算子 (===ltlt=gtおよび gt=) を使用できますApex は SOQL 比較セマンティックを使用するためStrings の結果はコンテキストユーザーのロケールに従って照合され大文字と小文字の区別はされません詳細は「演算子」 (ページ 42)を参照してください
String メソッド Java と同様String はさまざまな標準メソッドを使用して操作できます詳細は「String メソッド」を使用してください
言語構造 Version 180 | プリミティブデータ型 | 29
説明データ型
項目に割り当てた文字列値が長すぎる場合APIバージョン 150 以上を使用して保存 (コンパイル) した Apex クラスにはランタイムエラーが発生します
特定の時刻を示す値Time 値は必ずシステム静的メソッドを使用して作成する必要があります詳細は「Time メソッド」 (ページ 226)を参照してください
Time
また標準でない次の 2 つのプリミティブデータ型は変数またはメソッド型として使用できませんがシステム静的メソッドに表示されます
bull AnyTypevalueOf静的メソッドはデータ型 AnyType の sObject 項目を標準プリミティブデータ型に変換しますAnyType はForcecom プラットフォームで項目履歴管理表の sObject 項目専用で使用されます
bull CurrencyCurrencynewInstance静的メソッドはデータ型 Currency のリテラルを作成しますこのメソッドは SOQL および SOSL の WHERE句で独立して使用されsObject 通貨項目に対して絞り込みを行いますApex のその他のデータ型で Currency をインスタンス化できません
AnyType データ型の詳細は『Forcecom Web サービス API Developers Guide』のwwwsalesforcecomusdeveloperdocsapiindex_CSHhtmfield_typeshtm を参照してください
sObject 型この開発者ガイドではsObjectという用語はForcecomプラットフォームデータベースで保存できるオブジェクトのことを示しますsObject 変数はデータの行を示しオブジェクトのWeb サービスAPI名を使用してApexでのみ宣言できます例
Account a = new Account() MyCustomObject__c co = new MyCustomObject__c()
Web サービス API と同様Apex では汎用 sObject 抽象型を使用してオブジェクトを示しますsObject データ型は異なる種類の sObjects を処理するコードで使用できますsObjects は常にApexの参照によって渡されます
new演算子はコンクリート sObject 型を要求するためすべてのインスタンスは特定の sObjects です例
sObject s = new Account()
汎用 sObject 型と特定の sObject 型の間で投入を使用することもできます例
上記の例の汎用変数を 特定の取引先および取引先変数に投入します Account a = (Account)s 次はランタイムエラーを生成します Contact c = (Contact)s
sObjects はオブジェクトと同様に機能するため次のようになります
Object obj = s and a = (Account)obj
DML 操作は汎用 sObject データ型および正規の sObjects として宣言される変数を処理します
sObject 変数は nullに初期化されますがnew演算子を有効なオブジェクト参照に割り当てることができます例
Account a = new Account()
言語構造 Version 180 | sObject 型 | 30
新しい sObject をインスタンス化する場合開発者は最初の項目値にカンマで区切られた name = valueのペアを指定することもできます例
Account a = new Account(name = Acme billingcity = San Francisco)
Forcecom プラットフォームデータベースから既存の sObject へのアクセスの詳細は 「SOQL クエリおよびSOSL クエリ」 (ページ 55)を参照してください
メモ sObject の ID は読み取り専用の値で複製操作中にクリアされない限りまたはコンストラクタが割り当てられない限りApexで明示的に変更できませんForcecomプラットフォームはオブジェクトレコードが初めてデータベースに挿入されると ID 値を自動的に割り当てます詳細は「リスト」(ページ 34)を参照してください
カスタム表示ラベル
カスタムラベルは標準 sObjects ではありませんカスタムラベルの新規インスタンスを作成することはできませんカスタムラベルの値にはsystemlabellabel_nameを使用してのみアクセスできます例
String errorMsg = SystemLabelgeneric_error
カスタムラベルの詳細はSalesforcecom オンラインヘルプの「カスタムラベルの概要」を参照してください
sObject 項目へのアクセス
Java と同様sObject 項目は簡単なドット表記でアクセスまたは変更できます例
Account a = new Account() aname = Acme 取引先名項目にアクセスし割り当てます Acme
Created Byまたは Last Modified Dateなどシステムによって生成された項目は変更できません変更しようとするとApexランタイムエンジンはエラーを生成しますまた数式項目値およびコンテキストユーザーの読み取り専用のその他の項目の値も変更できません
汎用 sObject 型の場合Account など特定のオブジェクトではなくID 項目にのみ取得できます例
Account a = new Account(name = Acme billingcity = San Francisco) Insert a sObject s= [select id name from account where name = Acme limit 1] This is allowed ID id =sID The following lines result in errors when you try to save String x = sname sID= [select id from Account where name = Acme limit 1]
メモ 組織で個人取引先が有効になっている場合は法人取引先と個人取引先の 2 種類の取引先が使用できますスクリプトが nameを使用して新しい取引先を作成すると法人取引先が作成されますスクリプトが LastNameを使用する場合個人取引先を作成します
sObject に操作を実行する場合まず特定のオブジェクトに変換することをお勧めします例
Account a = new Account(name = Acme billingcity = San Francisco) Insert a sObject s= [select id name from account where name = Acme limit 1] ID id = sID AccountconvertedAccount = (Account)s convertedAccountname = Acme2 Update convertedAccountContact sal = new Contact(firstname = Sal account = convertedAccount)
言語構造 Version 180 | sObject 型 | 31
次の例はレコードのセットに SOSL をどのように使用してオブジェクトタイプを決定するかについて示しています汎用 sObject レコードを取引先担当者リードまたは取引先に変換すると項目をそれぞれ次のように変更できます
public class convertToCLA ListltContactgt contacts ListltLeadgt leads ListltAccountgt accounts
public void convertType(Integer phoneNumber) ListltListltsObjectgtgt results = [find4155557000 in phone fields returning contact(id phone firstname lastname) lead(idphone firstname lastname) account(id phone name)] sObject[] records =((ListltsObjectgt)results[0])
if (recordsisEmpty()) for (Integer i = 0 i lt recordssize() i++) sObject record =records[i] if (recordgetSObjectType() == ContactsObjectType) contactsadd((Contact)record) else if (recordgetSObjectType() == LeadsObjectType) leadsadd((Lead) record) else if (recordgetSObjectType() == AccountsObjectType) accountsadd((Account) record)
関係を介した sObject 項目へのアクセス
sObject レコードはID および関連する sObject の表現を示すアドレスという 2 つの項目でその他のレコードとの関係を示しますたとえばContact sObject にはデータ型 ID の AccountId項目と関連する Object 自体を示すデータ型 Account の Account項目があります
ID 項目を使用して連絡先と関連する取引先を変更しsObject 参照項目を使用して取引先のデータにアクセスすることができます参照項目はSOQL クエリまたは SOSL クエリの結果としてのみ投入されます (下記参照)
たとえばApex スクリプトは取引先と連絡先がお互いどのように関連しているか連絡先を使用して取引先の項目をどのように変更できるかを示しています
メモ 最も複雑な例を示すためにこのコードは本ガイドの後で説明される一部の要素を使用します
bull insertおよび updateの詳細は「挿入操作」 (ページ 192)および「更新操作」 (ページ 192)を参照してください
bull SOQL および SOSL の詳細は「SOQL クエリおよび SOSL クエリ」 (ページ 55)を参照してください
Account a = new Account(name = Acme) insert a レコードを挿入すると自動的に 値が ID 項目に割り当てられます Contact c = new Contact(lastName = Weissman) caccountId = aId 新しい連絡先は新しい取引先を示します insert c
SOQL クエリは投入された caccount など挿入された連絡先のデータにアクセスします field c =[select accountname from contact where id = cid]
両方のレコードの項目を連絡先によって変更できます caccountname = salesforcecom clastName= Roth
データベースを更新するには2 種類のレコードを 個別に更新する必要があります update c 連絡先の名前のみ変更します update caccount 取引先名を更新します
言語構造 Version 180 | sObject 型 | 32
メモ 表現 caccountnameは関係を切り返すその他の表現とともに変更されるときではなく値として読み込まれるときに若干異なる特性を表します
bull 値として読み込まれるときcaccountが null の場合 caccountnameは null を評価しますがNullPointerExceptionは生成しませんこのデザインにより開発者は null 値をチェックする必要があるという手間を省いて複数の関係をナビゲートできます
bull 変更されるときcaccountが null の場合caccountname は NullPointerExceptionを生成します
またsObject 項目キーは insertupdateまたは upsertとともに使用して外部 ID によって外部キーを解決します例
Account refAcct = new Account(externalId__c = 12345)
Contact c = new Contact(account = refAcct lastName = Kay)
insert c
新しい連絡先にexternal_idが「12345」である取引先と同じAccountIdを挿入しますそのような取引先がない場合挿入は失敗します
ヒント
たとえば次のコードは上記のコードと同一ですただしSOQL クエリを使用するためそれほど有効ではありませんこのコードが複数回コールされた場合SOQL クエリ最大数の実行制限に達する場合があります実行制限の詳細は「実行ガバナーと制限の理解」を参照してください
Account refAcct = [select id from Account where externalId__c=12345]
Contact c = new Contact(account = refAcctid)
Insert c
sObjects および項目の検証
Apex スクリプトが解析および検証される時すべての sObject および項目参照が実際のオブジェクト名および項目名に対して検証され無効な名前が使用されている場合解析時の例外が投げられます
またApex パーサーは埋め込み SOQL ステートメントおよび SOSL ステートメントおよびスクリプトの構文の両方で使用されているカスタムオブジェクトおよびカスタム項目を追跡します次のような変更によってApexスクリプトが無効になる場合プラットフォームを使用してユーザーが変更を行えないようにします
bull 項目名またはオブジェクト名の変更bull あるデータ型から別のデータ型への変換bull 項目またはオブジェクトの削除bull レコード共有項目履歴管理レコードの種類など特定の組織全体の変更
コレクションApex には次のようなコレクションがあります
bull リスト
言語構造 Version 180 | コレクション | 33
bull マップbull セット
メモ 保持できる項目の数については制限はありませんただしヒープサイズには制限があります
リスト
リストはプリミティブsObjectsユーザ定義のオブジェクトApex オブジェクトまたは他のコレクションの順序付けされ索引で区別されたコレクションですたとえば次の表には String のリストを視覚的に示しています
Index 5Index 4Index 3Index 2Index 1Index 0
PurpleBlueGreenYellowOrangeRed
リスト内の最初の要素の索引は必ず 0 となります
リストには他のコレクションを含めることができるため多次元的な定義が可能ですたとえばIteger のセットのリストのリストを作成できますリストではコレクションを 最大 5 段階ネストすることができます
リストを宣言するにはltgt文字で囲んだプリミティブデータ型sObjectネストされたリストマップセット型の前に Listキーワードを使用します例
String の空のリストを作成 ListltStringgt my_list = new ListltStringgt() ネスとされたリストを作成 ListltListltSetltIntegergtgtgt my_list_2 = new ListltListltSetltIntegergtgtgt() SOQL クエリから取引先レコードのリストを作成 ListltAccountgt accs = [SELECT Id Name FROM Account LIMIT 1000]
リストの要素にアクセスするにはApex で提供されたシステムメソッドを使用します例
ListltIntegergt MyList = new ListltIntegergt() 新しいリストを定義 MyListadd(47) 値 47 の 2 番目の要素を末尾に追加 of the list MyListget(0) index 0 で要素を取得 MyListset(0 1) 整数 1 を
index 0 のリストに追加 MyListclear() リストからすべての要素を削除
サポートされているメソッドの詳細は「List メソッド」 (ページ 227)を参照してくださいプリミティブまたは sObject の一次元リストの配列表記法の使用
プリミティブまたは sObjects の一次元リストを使用する場合従来の配列表記を使用してもリスト要素を宣言および参照することができますたとえば次のように [] 文字でデータ名または sObject 型名を囲んでプリミティブまたは sObject の一次元的リストを宣言することができます
String[] colors = new ListltStringgt()
プリミティブデータ型または sObjects の一次元リストの要素を参照するためにリスト名の後に要素の索引の位置を大かっこで囲んで表記します例
colors[3] = Green
言語構造 Version 180 | コレクション | 34
すべてのリストは nullに初期化されますリストには値を割り当てリテラル表記を使用してメモリを割り当てることができます例
説明例
要素のない Integer リストを定義しますListltIntegergt ints = new Integer[0]
要素のない Account リストを定義しますListltAccountgt accts = new Account[]
メモリを 6 つの Integer に割り当てた Integer リストを定義します
ListltIntegergt ints = new Integer[6]
最初の場所に新しい Account オブジェクト2 番目にnull3 番目の場所に別の新しい Account オブジェク
ListltAccountgt accts = new Account[] newAccount() null new Account()
トなど 3 つの Account にメモリを割り当てた Accountリストを定義します
与えられた要素を含む新しい Contact リストを定義します
ListltContactgt contacts = new ListltContactgt(otherList)
sObjects のリスト
Apex はリストがデータ操作言語 (DML) ステートメントを含むデータベースに正常に挿入されると自動的にsObject のリストの各オブジェクトに ID を生成しますその結果同じ sObject を複数回含む場合null ID を持つ場合でもsObject のリストを挿入することはできませんこれは2 つの ID をメモリ内の同じ構造内に書き込む必要があるということは違反であることを示しています
たとえば次のコードブロックの insertステートメントは同じ sObject (a) への参照を 2 つ持つリストを挿入しようとしているためListExceptionを生成します
try
同じ sObject 要素への 2 つの参照を持つリストを作成 Account a = new Account() Account[] accs= new Account[]a a
挿入を試行 insert accs
取得せず Systemassert(false) catch (ListException e) ここで取得
DML ステートメントの詳細は「Apex のデータ操作言語 (DML) 操作」 (ページ 186)を参照してください
汎用 sObject データ型にリストを使用することができますリストの汎用インスタンスを作成することもできます
セット
セットは重複する要素を含まないプリミティブデータ型の順不同のコレクションですたとえば次の表には都市名のセットを示します
TokyoParisNew YorkSan Francisco
言語構造 Version 180 | コレクション | 35
セットを宣言するにはltgt 文字で囲んだプリミティブデータ型の前に Setキーワードを使用します例
new SetltStringgt()
次のようにしてセットを宣言し投入します
SetltStringgt s1 = new SetltStringgta b + c 2 つの要素を持つ新しいセットを定義 SetltStringgts2 = new SetltStringgt(s1) 以前の手順で作成されたセットの要素 を含む新しいセットを定義します
セットの要素にアクセスするにはApex で提供されたシステムメソッドを使用します例
SetltIntegergt s = new SetltIntegergt() 新しいセットを定義 sadd(1) 要素をセットに追加 Systemassert(scontains(1)) セットに要素が含まれていることを確
認 sremove(1) セットから要素を削除
サポートされているセットシステムメソッドの詳細は「Set メソッド」 (ページ 234)を参照してください
セットについて次の点に注意してください
bull Java と異なりApex 開発者は宣言でマップを実装するために使用するアルゴリズムを参照する必要がありません (HashSetまたは TreeSetなど)Apex はすべてのセットにハッシュ構造を使用します
bull セットは順序のないコレクションですセットの結果が返される順序に依存しないでくださいセットによって返されるオブジェクトの順序は警告なく変更される場合があります
マップ
マップは一意のキーを単一の値に対応付けるキー 値のペアのコレクションですキーはプリミティブデータ型で値はプリミティブsObjectコレクション型または Apex オブジェクトとなりますたとえば次の表は国名と通貨のマップを示します
IndiaEnglandFranceJapanUnited States国 (キー)
RupeePoundEuroYenDollar通貨 (値)
リストと同様マップの値にはコレクションを含める事ができネストすることが可能ですたとえばIntegerのマップをマップしたりString をリストにマップすることができますマップではコレクションを最大 5 段階ネストすることができます
マップを宣言するにはltgt 文字で囲んだキーおよび値のデータ型の前に Mapキーワードを使用します例
MapltString Stringgt country_currencies = new MapltString Stringgt() MapltID SetltStringgtgt m= new MapltID SetltStringgtgt() MapltID MapltID Account[]gtgt m2 = new MapltID MapltIDAccount[]gtgt()
汎用 sObject データ型にマップを使用することができますマップの汎用インスタンスを作成することもできます
リスト同様マップを中かっこ () 構文を使用して宣言する場合マップのキー-値のペアを投入することができます中かっこの中でキーを最初に指定し=gtを使用してキーの値を指定します例
MapltString Stringgt MyStrings = new MapltString Stringgta =gt b c =gt dtoUpperCase()
言語構造 Version 180 | コレクション | 36
Account[] accs = new Account[5] Account[] は ListltAccountgt と同じです MapltIntegerListltAccountgtgt m4 = new MapltInteger ListltAccountgtgt1 =gt accs
最初の例でキー aの値は bでキー cの値は dです2 番目の例でキー 1にはリスト accsの値が含まれます
マップの要素にアクセスするにはApex で提供されたシステムメソッドを使用します例
Account myAcct = new Account() 新しい取引先を定義 MapltIntegerAccountgt m = new MapltInteger Accountgt() 新しいマップを定義 mput(1 myAcct)
マップに新しいキー-値を挿入 Systemassert(mcontainsKey(3)) マップにキーが含まれていることを確認 Account a = mget(1) 特定のキーを指定して値を取得 SetltIntegergt s =mkeySet() マップのすべてのキーを含むセットを返す
サポートされているマップシステムメソッドの詳細は「Map メソッド」 (ページ 231)を参照してください
マップについて次の点に注意してください
bull Java と異なりApex 開発者は宣言でマップを実装するために使用するアルゴリズムを参照する必要がありません (HashMapまたは TreeMapなど)Apex はすべてのマップにハッシュ構造を使用します
bull マップの結果が返される順序に依存しないでくださいマップによって返されるオブジェクトの順序は警告なく変更される場合がありますマップ要素には常にキーによってアクセスします
SObject 配列からのマップ
ID または String データ型から sObject へのマップはsObjects のリストから初期化できますオブジェクトの ID(null 以外の重複しない値) はキーとして使用されますこのマップ型の一般的な使用方法は2 つの表の間でメモリ内「結合」するためのものですたとえばこの例では ID と Contact のマップをロードします
MapltID Contactgt m = new MapltID Contactgt([select id lastname from contact])
例ではSOQL クエリは id項目 lastname項目を含む連絡先のリストを返しますnew演算子はリストを使用してマップを作成します詳細は「SOQL クエリおよび SOSL クエリ」 (ページ 55)を参照してください
コレクションの繰り返し処理
コレクションはリストセットまたはマップで構成されますコレクションの繰り返し処理中にコレクションの要素を変更することはできません変更するとエラーが発生します要素を含むコレクションを繰り返し処理中に要素を直接追加したり削除しないでください
繰り返し処理中の要素の追加
リストセットまたはマップの繰り返し処理中に要素を追加するには新しい要素を一時的なリストセットまたはマップに保存しコレクションの処理が終了した後で元のコレクションに追加します
繰り返し処理中の要素の削除
リストの繰り返し処理中に要素を削除するには新しいリストを作成し保存する要素をコピーしますまたは削除する要素を一時的なリストに追加してコレクションの処理が終了した後で削除することもできます
メモ
Listremoveメソッドが一次的に実行しますこのメソッドを使用して要素を削除することは時間と人員の点で意味があります
言語構造 Version 180 | コレクション | 37
マップまたはセットの繰り返し処理中に要素を削除するには削除するキーを一時的なリストに保存しコレクションの処理が終了した後で削除します
Enum
enum は指定された識別子の有限の集合から つだけを値に持つ抽象データ型ですEnumは通常トランプや季節など特定の数値 順序を持たない値のセットを定義しますenum の各値はユニークな整数値を持ちますがenum の内部処理のみに利用されており不用意に間違って数値処理等の対象としないよう実装を隠していますenum を作成した後変数メソッド引数戻り型を該当するデータ型に宣言します
メモ Java と異なりenum 型自体にはコンストラクタ構文はありません
enumを定義するには宣言でenumキーワードを使用し中かっこを使用して値のリストを区画しますたとえば次のコードは Seasonという enum を作成します
public enum Season WINTER SPRING SUMMER FALL
enum Seasonを作成してSeasonという新しいデータ型も作成します他のデータ型と同じようにこの新しいデータ型を使用できます例
Season e = SeasonWINTER
Season m(Integer x Season e)
If (e == SeasonSUMMER) return e
クラスを enum に定義することもできますenum クラスを作成する場合定義で classキーワードを使用しません
public enum MyEnumClass X Y
enum は他のデータ型の名前を使用する場所であればどこででも使用できます型が enum である変数を定義する場合それに割り当てるオブジェクトはその enum のインスタンスでなければなりません
webServiceメソッドは enum 型を署名の一部として使用できますこの場合関連する WSDL ファイルにはenum およびその値の定義が含まれAPI クライアントによって使用できます
Apex には次のようなシステム定義 enum があります
bull SystemStatusCode
この enum はすべての API 演算子の WSDL で表示される API エラーコードに対応しています例
StatusCodeCANNOT_INSERT_UPDATE_ACTIVATE_ENTITYStatusCodeINSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY
ステータスコードの完全なリストは組織の WSDL ファイルから入手できます組織の WSDL ファイルへのアクセスの詳細はSalesforcecomオンラインヘルプの「Salesforcecom WSDL およびクライアント認証証明書のダウンロード」を参照してください
bull SystemXmlTag
言語構造 Version 180 | Enum | 38
この enum はwebServiceメソッドの結果 XML を解析するために使用する XML タグのリストを返します詳細は「XmlStreamReaderクラス」 (ページ 366)を参照します
bull SystemLoggingLevel
この enum は systemdebugメソッドを使用してすべての debugコールのログレベルを指定します詳細は「システムメソッド」 (ページ 285)を参照してください
bull SystemRoundingMode
この enum はDecimal divideメソッドおよび Double roundメソッドなど処理の丸め動作を指定する数学的処理を実行するメソッドによって使用されます詳細は「丸めモード」 (ページ217)を参照してください
bull SystemSoapType
この enum は項目記述結果の getSoapTypeメソッドによって返されます詳細は「SchemaSOAPTypeEnum 値 (ページ 256)」を参照してください
bull SystemDisplayType
この enum は項目記述結果の getTypeメソッドによって返されます詳細は「SchemaDisplayType Enum値 (ページ 254)」を参照してください
bull ApexPagesSeverity
この enum はVisualforce メッセージの重要度を指定します詳細は「ApexPagesSeverity Enum」 (ページ326)を参照してください
bull DomXmlNodeType
DOM ドキュメントのノードの種類を指定します詳細は「ノードの種類 (ページ 357)」を参照してください
メモ システム定義の enum は Web サービスメソッドで使用することはできません
システム enum のすべての enum 値にはそれらに関連する共通メソッドがあります詳細は「Enum メソッド」 (ページ 237)を参照してください
ユーザー定義のメソッドを enum 値に追加することができません
変換の規則について通常Apexではあるデータ型を別のデータ型に変換する場合明示的に指示する必要がありますたとえばInteger データ型の変数を暗黙的に String に変換することはできませんstringformatメソッドを使用する必要がありますただし一部のデータ型ではメソッドを使用せず暗黙的に変換することができます
精度の低い数値型は明示的な変換をせずにより高精度の数値型に割り当てる事ができます次に示すのは数値の階層です (精度が低い方順に並んでいます)
1 Integer2 Long3 Double4 Decimal
メモ 値が精度の低い型から高い型に渡されると値は高い精度を持つ型に変換されます
言語構造 Version 180 | 変換の規則について | 39
この数値の階層と暗黙的な変換は元のインターフェースの数値が維持され暗黙の変換を禁止する Java とは異なります
数値のほかにも暗黙的に変換されるデータ型があります以下の規則が適用されます
bull ID は必ず String に割り当てることができますbull String は ID に割り当てることができますただし実行時値が正当な ID であることを確認します正当で
ない場合ランタイム例外が発生しますbull instanceOfキーワードにより文字列が ID であるかどうかいつでもテストできます
変数
ローカル変数はJava スタイルの構文で宣言されます例
Integer i = 0 String str Account a Account[] accts SetltStringgt s MapltID Accountgt m
Java と同様カンマ区切り形式を使用して複数の変数を単一のステートメントで宣言および初期化することができます例
Integer i j k
すべての変数は nullを値とすることができ別の値が割り当てられていない場合は nullに初期化されますたとえば次の例ではiおよび kには値が割り当てられjには値が割り当てられていないためnullに設定されます
Integer i = 0 j k = 1
変数はブロック内のどの場所でも定義できその場所から先のスコープとなりますサブブロックはすでに親ブロックで使用されている変数名を再定義できませんが並行ブロックは変数名を再利用できます例
Integer i Integer i この宣言は無効です
for (Integer j = 0 j lt 10 j++) for (Integer j = 0 j lt 10 j++)
大文字と小文字の区別大文字と小文字を区別しない SOQL および SOSL クエリとの混乱を避けるためApex も大文字と小文字の区別をしませんつまり次のようになります
bull 変数名とメソッド名は大文字と小文字の区別をしません例
Integer I Integer i これはエラーです
bull オブジェクト名および項目名への参照は大文字と小文字の区別をしません例
Account a1 ACCOUNT a2
言語構造 Version 180 | 変数 | 40
bull SOQL および SOSL ステートメントは大文字と小文字の区別をしません例
Account[] accts = [sELect ID From ACCouNT where nAme = fred]
またApex はSOQL と同じフィルタリングセマンティックを使用しますそれはAPI と Salesforcecom ユーザーインターフェースとの比較の基本となりますこれらのセマンティックを使用すると興味深い動作が発生しますたとえばエンドユーザーがアルファベットの「m」の前以前の値の条件 (つまり値 ltm) でレポートを実行するとnull 項目が結果の一部として返されますこれはすなわちユーザーは通常値を持たない項目について実際の「null」値ではなく単なる「スペース」文字として考えるということですそのためApexでは次の表現はすべて真に評価します
String s Systemassert(a == A) Systemassert(s lt b) Systemassert((s gt b))
メモ 上記の例では s lt bは真に評価しますが文字を null 値と比較しようとするためbcompareTo(s)はエラーを生成します
定数定数はfinalキーワードを使用して定義できます値は宣言自体でまたは定数がクラス内で定義されている場合は静的初期化子メソッドで一度のみ割り当てることができます例
public class myCls static final Integer PRIVATE_INT_CONST static finalInteger PRIVATE_INT_CONST2 = 200
public static Integer calculate() return 2 + 7
static PRIVATE_INT_CONST = calculate()
詳細は「finalキーワードの使用」 (ページ 102)を参照してください
式
式は変数演算子単一の値を評価するメソッド呼び出しで構成されますこの項ではApex の式の概要および以下のトピックについて説明しています
bull 式の理解 (ページ 41)bull 式の演算子について (ページ 42)bull 演算子の優先度について (ページ 48)bull sObject 式およびリスト式の拡張 (ページ 49)bull コメントの使用 (ページ 49)
式について式は変数演算子単一の値を評価するメソッド呼び出しで構成されますApex の場合式は次のタイプのいずれかでなければなりません
言語構造 Version 180 | 定数 | 41
bull リテラル式例
1 + 1
bull 新しい sObjectApex オブジェクトリストセットまたはマップ例
new Account(ltfield_initializersgt) new Integer[ltngt] new Account[]ltelementsgt newListltAccountgt() new SetltStringgt new MapltString Integergt() new myRenamingClass(stringoldName string newName)
bull 変数一次元リストの場所多くの sObject または Apex オブジェクト項目の参照など代入演算子の左側として機能できる値 (L-値)例
Integer i myList[3] myContactname myRenamingClassoldName
bull sObject 項目参照L-値ではなく次のようなものがあります
- リストの sObject の ID (「リスト」を参照してください)- sObject に関連する子レコードのセット (親取引先と関連する連絡先のセットなど)この種類の式は
「SOQL クエリおよび SOSL クエリ」と同様クエリ結果を生成します
bull 大かっこで囲まれた SOQL クエリまたは SOSL クエリApex で容易に評価できます例
Account[] aa = [select id name from account where name =Acme] Integer i = [selectcount() from contact where lastname =Weissman] ListltListltSObjectgtgt searchList = [FINDmap IN ALL FIELDS RETURNING Account (id name) Contact Opportunity Lead]
詳細は「SOQL クエリおよび SOSL クエリ」 (ページ 55)を参照してくださいbull 静的メソッドまたはインスタンスメソッドの呼び出し例
Systemassert(true) myRenamingClassreplaceNames() changePoint(new Point(x y))
式の演算子について演算子を使用して式をお互いに結合し複合式を作成することができますApex では次の演算子を使用できます
説明構文演算子
代入演算子 (右結合)yの値を L-値 xに割り当てますxのデータ型は yのデータ型と一致する必要がありnullとなることはできません
x = y=
加算代入演算子 (右結合)yの値を xの元の値に追加しxに新しい値を再代入します詳細は+を参照してくださいxおよび yをnullとすることはできません
x += y+=
乗算代入演算子 (右結合)yの値を xの元の値に乗算しxに新しい値を再代入しますxおよび yは Integer または Doubleまたは組み
x = y=
言語構造 Version 180 | 式の演算子について | 42
説明構文演算子
合わせである必要がありますxおよび yを nullとすることはできません
減算代入演算子 (右結合)yの値を xの元の値から減算しxに新しい値を再代入しますxおよび yは Integer または Doubleまたは組
x -= y-=
み合わせである必要がありますxおよび yを nullとすることはできません
除算代入演算子 (右結合)yの元の値を xで除算しxに新しい値を再代入しますxおよび yは Integer または Doubleまたは組み合わ
x = y=
せである必要がありますxおよび yを nullとすることはできません
OR 代入演算子 (右結合)xが Boolean かつ yが Boolean でいずれも偽である場合xは偽のままとなりますそうでない場合xには真の値を代入します
メモ
x |= y|=
bull この演算子は「短絡な」動作を示しyはxが偽の場合にのみ評価されます
bull xおよび yを nullとすることはできません
AND 代入演算子 (右結合)xが Boolean かつ yが Boolean でいずれも真である場合xは真のままとなりますそうでない場合xには偽の値を代入します
メモ
x amp= yamp=
bull この演算子は「短絡な」動作を示しyはxが真の場合にのみ評価されます
bull xおよび yを nullとすることはできません
ビット単位の左シフト代入演算子xの各ビットをyビットで左にシフトします上位の順番のビットが失われ新しい右側のビットが 0に設定されますこの値は xに再代入されます
x ltlt= yltlt=
ビット単位の右シフト符号付き代入演算子xの各ビットをyビットで右にシフトします回の順番のビットが失われ新しい左のビッ
x gtgt= ygtgt=
トがyが正の値の場合 0 にyが負の値の場合 1 に設定されますこの値は xに再代入されます
ビット単位の右シフト符号なし代入演算子xの各ビットをyビットで右にシフトします下位の順番のビットが失われyのすべての値
x gtgtgt= ygtgtgt=
について新しい左側のビットが 0 に設定されますこの値は xに再代入されます
3 項演算子 (右結合)この演算子はif-then-else ステートメントの短縮として機能しますxが Boolean で真の場合yが結果となります
x y z
そうでない場合zが結果となりますxを nullとすることはできません
言語構造 Version 180 | 式の演算子について | 43
説明構文演算子
AND 論理演算子 (左結合)xが Boolean かつ yが Boolean でいずれも真である場合式は真に評価しますそうでない場合式は偽に評価します
メモ
x ampamp yampamp
bull ampampは ||より優先されますbull この演算子は「短絡な」動作を示しyはxが真の場合にのみ評
価されますbull xおよび yを nullとすることはできません
OR 論理演算子 (左結合)xが Boolean かつ yが Boolean でいずれも偽である場合式は偽に評価しますそうでない場合式は真に評価します
メモ
x || y||
bull ampampは ||より優先されますbull この演算子は「短絡な」動作を示しyはxが偽の場合にのみ評
価されますbull xおよび yを nullとすることはできません
等価演算子xの値がyの値に等しい場合式は真に評価しますそうでない場合式は偽に評価します
メモ
x == y==
bull Java とは異なりApex の ==は参照の等式ではなくオブジェクト値の等式を比較します結果次のようになります
- ==を使用した文字列の比較では大文字と小文字を区別しません
- ==を使用した ID の比較では大文字と小文字を区別し15 文字の形式および 18 文字の形式を区別しません
bull sObjects および sObject の配列に対し==は結果を返す前にすべての sObject に詳細なチェックを実行します
bull レコードに対し各項目には真に評価する ==の値が含まれている必要があります
bull xまたは yをリテラルの nullとすることができますbull 2 つの値の比較により nullとなることはありませんbull SOQL および SOSL では==ではなく等価演算子の =を使用
しますApexと SOQL および SOSL は強くリンクしていますが多くの近代言語では代入に =そして等式に ==を使用するため構文の不一致が発生しますApexのデザイナーは開発者が新しい代入演算子を学ばずにこのパラダイムを維持することが重要であると考えていますその結果Apex開発者は主要なスクリプト本文で ==を等式テストにそして SOQL クエリおよび SOSL クエリの =等式に使用する必要があります
言語構造 Version 180 | 式の演算子について | 44
説明構文演算子
厳密な等価演算子xおよびyがメモリ内のまったく同じ場所を参照する場合式は真に評価しますそうでない場合式は偽に評価しま
x === y===
すこの演算子は sObjects またはコレクション (マップまたはリストなど) のみを処理しますApex オブジェクト (例外またはクラスのインスタンス化など) の場合厳密な等価演算子は等価演算子と同じです
小なり演算子xがyより小さい場合式は真に評価しますそうでない場合式は偽に評価します
メモ
x lt ylt
bull その他のデータベースストアドプロシージャと異なりApexでは3 状態 Boolean ロジックはサポートされておらず2 つの値の比較によって nullとなることはありません
bull xまたは yが nullで IntegerDoubleDateまたは Datetime となる場合式は偽となります
bull null以外の String または ID 値は常に null値より大きくなります
bull xおよびyが ID の場合それらは同じデータ型のオブジェクトを参照する必要がありますそうでない場合ランタイムエラーが発生します
bull xまたは yのいずれかが ID でもう一方が String の場合String 値は ID として検証され処理されます
bull xおよび yはBoolean とすることはできませんbull 2 つの文字列の比較はコンテキストユーザーのロケールにした
がって実行されます
大なり演算子xがyより大きい場合式は真に評価しますそうでない場合式は偽に評価します
メモ
x gt ygt
bull 2 つの値の比較により nullとなることはありませんbull xまたは yが nullで IntegerDoubleDateまたは Datetime と
なる場合式は偽となりますbull null以外の String または ID 値は常に null値より大きくなりま
すbull xおよびyが ID の場合それらは同じデータ型のオブジェクトを
参照する必要がありますそうでない場合ランタイムエラーが発生します
bull xまたは yのいずれかが ID でもう一方が String の場合String 値は ID として検証され処理されます
bull xおよび yはBoolean とすることはできませんbull 2 つの文字列の比較はコンテキストユーザーのロケールにした
がって実行されます
言語構造 Version 180 | 式の演算子について | 45
説明構文演算子
以下演算子xがyより小さいまたは等しい場合式は真に評価しますそうでない場合式は偽に評価します
メモ
x lt= ylt=
bull 2 つの値の比較により nullとなることはありませんbull xまたは yが nullで IntegerDoubleDateまたは Datetime と
なる場合式は偽となりますbull null以外の String または ID 値は常に null値より大きくなりま
すbull xおよびyが ID の場合それらは同じデータ型のオブジェクトを
参照する必要がありますそうでない場合ランタイムエラーが発生します
bull xまたは yのいずれかが ID でもう一方が String の場合String 値は ID として検証され処理されます
bull xおよび yはBoolean とすることはできませんbull 2 つの文字列の比較はコンテキストユーザーのロケールにした
がって実行されます
以上演算子xがyより大きいまたは等しい場合式は真に評価しますそうでない場合式は偽に評価します
メモ
x gt= ygt=
bull 2 つの値の比較により nullとなることはありませんbull xまたは yが nullで IntegerDoubleDateまたは Datetime と
なる場合式は偽となりますbull null以外の String または ID 値は常に null値より大きくなりま
すbull xおよびyが ID の場合それらは同じデータ型のオブジェクトを
参照する必要がありますそうでない場合ランタイムエラーが発生します
bull xまたは yのいずれかが ID でもう一方が String の場合String 値は ID として検証され処理されます
bull xおよび yはBoolean とすることはできませんbull 2 つの文字列の比較はコンテキストユーザーのロケールにした
がって実行されます
不等価演算子xの値がyの値と等しくない場合式は真に評価しますそうでない場合式は偽に評価します
メモ
x = y=
bull Java とは異なりApex の =は参照の等式ではなくオブジェクト値の等式を比較します
bull sObjects および sObject の配列に対し=は結果を返す前にすべての sObject に詳細なチェックを実行します
言語構造 Version 180 | 式の演算子について | 46
説明構文演算子
bull レコードについてレコードに項目のさまざまな値がある場合=
は真に評価しますbull xまたは yをリテラルの nullとすることができますbull 2 つの値の比較により nullとなることはありません
厳密な不等価演算子xおよびyがメモリ内のまったく同じ場所を参照しない場合式は真に評価しますそうでない場合式は偽に評価
x == y==
しますこの演算子は sObjects またはコレクション (マップまたはリストなど)または Apex オブジェクト (クラスの例外またはインスタンス化) のみを処理します
加算演算子次のルールに従ってxの値を yの値に追加しますx + y+
bull xおよび yが Integer または Double の場合xの値は yの値に追加しますDouble が使用されると結果は Double となります
bull xが Date で yが Integer の場合指定した日数で増加した新しいDate を返します
bull xが Datetime で yが Integer または Double の場合日の部分に対応する分数部分で指定した日数で増加した新しい Date を返します
bull xが String で yが String またはその他のデータ型の null以外の引数である場合yを xの終わりに連結します
減算演算子次のルールに従ってyの値からyの値を減算しますx - y-
bull xおよび yが Integer または Double の場合xの値を yの値から引きますDouble が使用されると結果は Double となります
bull xが Date で yが Integer の場合指定した日数分減少した新しいDate を返します
bull xが Datetime で yが Integer または Double の場合日の部分に対応する分数部分で指定した日数分減少した新しい Date を返します
乗算演算子Integer または Double の xと別の Integer または Doubleである yを乗算しますDouble が使用されると結果は Double となります
x y
除算演算子Integer または Double の xを別の Integer または Doubleである yで除算しますDouble が使用されると結果は Double となります
x y
論理補数演算子Boolean の値を反転し真は偽に偽を真にします
x
単項否定演算子Integer または Double の xを -1 で乗算します正の等価 +も構文的に有効ですが数学的に影響はありません
-x-
インクリメント演算子1 を Integer または Double である xの値に追加します前に記述した場合 (++x)ステートメントの残りが実行さ
x++
++x
++
言語構造 Version 180 | 式の演算子について | 47
説明構文演算子
れる前に増加します後に記述した場合 (++x)ステートメントの残りが実行された後に増加します
デクリメント演算子1 を Integer または Double である xの値から減算します前に記述した場合 (--x)ステートメントの残りが実行さ
x--
--x
--
れる前に減算します後に記述した場合 (x--)ステートメントの残りが実行された後に減算します
ビット単位の AND 演算子xの各ビットと yの対応するビットをAND 演算します両方のビットが 1 に設定されると結果ビットは 1
x amp yamp
に設定されますこの演算子は Long または Integer には使用できません
ビット単位の OR 演算子xの各ビットと yの対応するビットを OR演算します少なくとも 1 つのビットが 1 に設定されると結果ビット
x | y|
は 1 に設定されますこの演算子は Long または Integer には使用できません
ビット単位の排他的 OR 演算子xの各ビットと yの対応するビットに排他的な OR 演算をします1 つのビットが 1 に設定されもう一方が 0 に設定されると結果ビットは 1 に設定されます
x ^ y^
ビット単位の排他的 OR 演算子xの各ビットと yの対応するビットに排他的な OR 演算をします1 つのビットが 1 に設定されもう一方が 0 に設定されると結果ビットは 1 に設定されます
x ^= y^=
ビット単位の左シフト演算子xの各ビットをyビットで左にシフトします上位の順番のビットが失われ新しい右側のビットが 0 に設定されます
x ltlt yltlt
ビット単位の右シフト符号付き演算子xの各ビットをyビットで右にシフトします回の順番のビットが失われ新しい左のビットがyが正の値の場合 0 にyが負の値の場合 1 に設定されます
x gtgt ygtgt
ビット単位の右シフト符号なし演算子xの各ビットをyビットで右にシフトします下位の順番のビットが失われyのすべての値について新しい左側のビットが 0 に設定されます
x gtgtgt ygtgtgt
小かっこ式xの優先度を結合式で最初に評価されるようにします
(x)()
演算子の優先度についてApex では次の演算子優先度の規則を使用しています
説明演算子優先度
グループと前置インクリメントおよびデクリメント
() ++ --1
言語構造 Version 180 | 演算子の優先度について | 48
説明演算子優先度
単項否定型変換およびオブジェクト作成 -x +x (type) new2
乗算および除算 3
加算および減算+ -4
大なり記号および小なり記号参照テストlt lt= gt gt= instanceof5
比較子 等しい等しくない== =6
論理的 ANDampamp7
論理的 AND||8
代入演算子= += -= = = amp=9
sObject 式およびリスト式の拡張Java と同様sObject 式とリスト式はメソッド参照およびリスト式をそれぞれ使用して拡張子新しい式を形成することができます
次の例では新しい取引先名の長さを含む新しい変数が acctNameLengthに割り当てられます
Integer acctNameLength = new Account[]new Account(name=Acme)[0]namelength()
上記ではnew Account[]はリストを生成します
このリストはSOQL ステートメント new Account(name=Acme)によって入力されます
Item 0つまりリストの最初の項目は文字列 [0]の次の部分によってアクセスされます
リストの sObject の名前にアクセスし長さ namelength()を返すメソッドが続きます
次の例では小文字にシフトした名前が返されます
String nameChange = [SELECT Name FROM Account][0]NametoLowerCase()
コメントの使用Apex スクリプトでは単一のコメントおよび複数のコメントを使用できます
bull 1 行のコメントを作成するにはを使用しますの右側の同じ行にあるすべての行がパーサーによって無視されます例
Integer i = 1 このコメントはパーサーによって無視されます
bull 複数のコメントを作成するにはおよび を使用してコメントブロックの最初と最後を指定します例
Integer i = 1 このコメントはパーサーに中断されることなく複数行にわたることができます
言語構造 Version 180 | sObject 式およびリスト式の拡張 | 49
代入ステートメント
代入ステートメントは次の 2 つのいずれかの方法で値を変数に代入するステートメントです
[LValue] = [new_value_expression] [LValue] = [[inline_soql_query]]
上記の形式で[LValue]は代入演算子の左側に投入できる式を表しますその具体的な内容は次のとおりです
bull 単純な変数例
Integer i = 1 Account a = new Account() Account[] accts = [select id from account]
bull 参照が解決されたリスト要素例
ints[0] = 1 accts[0]name = Acme
bull コンテキストユーザーが編集する権限を持つ sObject 項目参照例
Account a = new Account(name = Acme billingcity = San Francisco)
ID は手動で設定できません aid = 00300000003T2PGAA0 このコードは無効です
代わりにレコードを挿入します自動的に ID を挿入します insert a
コンテキストユーザーはこの項目の書き込み権限を割り当てられている必要があります acreatedDate= Systemtoday() このコードは createdDate が読み取り専用であるため無効です
取引先が追加されているため関連する 新しい連絡先を作成することができます Contact c = newContact(lastname = Roth account = a)
連絡先を使用して取引先名に直接書き込むことができます caccountname = salesforcecom
代入は必ず参照によって行われます例
Account a = new Account() Account b Account[] c = new Account[] aname = Acme b =a cadd(a)
真であることを確認します取引先 b および取引先リスト c を介して 元来取引先 a に割り当てられていたデータを参照することができます SystemassertEquals(bname Acme)SystemassertEquals(c[0]name Acme)
同様に2 つのリストはメモリ内の同じ値を示すことができます例
Account[] a = new Account[]new Account() Account[] b = a a[0]name = AcmeSystemassert(b[0]name == Acme)
=のほか有効な割り当て演算子には +===|=amp=++および --があります詳細は「式の演算子について」 (ページ 42)を参照してください
言語構造 Version 180 | 代入ステートメント | 50
条件 (If-Else) ステートメント
Apex の条件ステートメントはJava と同じように動作します
if ([Boolean_condition]) Statement 1 else Statement 2
elseの部分は常にオプションで最も近い ifでグループ化されます例
Integer x sign Your code if (x lt= 0) if (x == 0) sign = 0 else sign = -1
次と同等となります
Integer x sign Your code if (x lt= 0) if (x == 0) sign = 0 else sign = -1
繰り返しの else ifステートメントも使用できます例
if (place == 1) medal_color = gold else if (place == 2) medal_color = silver else if (place == 3) medal_color = bronze else medal_color = null
ループ
Apex では次の 5 種類の手続き型ループをサポートしています
bull do statement while (Boolean_condition)
bull while (Boolean_condition) statement
bull for (initialization Boolean_exit_condition increment) statement
bull for (variable array_or_set) statement
bull for (variable [inline_soql_query]) statement
すべてのループは以下のループ制御構文を使用できます
bull breakループ全体を終了しますbull continueループの次の反復にスキップします
Do-While ループApex do-whileループは特定の Boolean 条件が真である限りコードのブロックを繰り返し実行します構文は次のとおりです
do code_block while (condition)
メモ 中かっこ () が必ず code_blockを囲みます
言語構造 Version 180 | 条件 (If-Else) ステートメント | 51
Java と同様Apex do-whileループは最初のループが実行されるまでBoolean 条件ステートメントをチェックしませんその結果コードブロックは最低 1 回実行されます
例として次のコードは1 - 10 の数値をデバッグログに出力します
Integer count = 1
do Systemdebug(count) count++ while (count lt 11)
While ループApexwhileループは特定の Boolean 条件が真である限りコードのブロックを繰り返し実行します構文は次のとおりです
while (condition) code_block
メモ 中かっこ () は複数のステートメントが含まれている場合にのみ code_blockを囲む必要があります
do-whileと異なりwhile lループは最初のループが実行される前に Boolean 条件ステートメントをチェックしますその結果コードブロックが実行されない場合もあります
例として次のコードは1 - 10 の数値をデバッグログに出力します
Integer count = 1
while (count lt 11) Systemdebug(count) count++
For ループApex では3 種類の forループを使用できます
bull 従来の forループ
for (init_stmt exit_condition increment_stmt) code_block
bull リスト反復またはセット反復の forループ
for (variable list_or_set) code_block
この場合 variableは list_or_setと同じプリミティブデータ型または sObject 型と同じである必要がありません
bull SOQL forループ
for (variable [soql_query]) code_block
or
for (variable_list [soql_query]) code_block
言語構造 Version 180 | While ループ | 52
variableおよび variable_listは soql_queryで返される sObject と同じデータ型でなければなりません
メモ 中かっこ () は複数のステートメントが含まれている場合にのみ code_blockを囲む必要があります
それぞれについて後の項で詳細に説明されています
従来の For ループ
Apex の従来の forループはJava およびその他の言語で使用される従来の構文に対応しています構文は次のとおりです
for (init_stmt exit_condition increment_stmt) code_block
この種類の forループを実行するとApex ランタイムエンジンは次のステップを順番に実行します
1 ループの init_stmtコンポーネントを実行します複数の変数をステートメントで宣言および初期化できます
2 exit_conditionチェックを実行します真の場合ループが続行します偽の場合ループが終了します3 code_blockを実行します4 increment_stmtステートメントを実行します5 ステップ 2 に戻ります
例として次のコードは1 - 10 の数値をデバッグログに出力します追加の初期化変数jを使用して構文を実証します
for (Integer i = 0 j = 0 i lt 10 i++) Systemdebug(i+1)
リスト反復またはセット反復の For ループ
リスト反復またはセット反復の forループを使用するとリスト内またはセット内のすべての要素を反復します構文は次のとおりです
for (variable list_or_set) code_block
この場合 variableは list_or_setと同じプリミティブデータ型または sObject 型と同じである必要がありません
この種類の forループを実行するとApex ランタイムエンジンは variableを list_or_setの各要素に割り当て各値の code_blockを実行します
たとえば次のコードは1 - 10 の数値をデバッグログに出力します
Integer[] myInts = new Integer[]1 2 3 4 5 6 7 8 9 10
for (Integer i myInts) Systemdebug(i)
言語構造 Version 180 | For ループ | 53
SOQL For ループ
SOQL forループは SOQL クエリで返されたすべての sObject レコードを反復しますSOQL forループの構文は次のいずれかになります
for (variable [soql_query]) code_block
or
for (variable_list [soql_query]) code_block
variableおよび variable_listは soql_queryで返される sObject と同じデータ型でなければなりません標準 SOQL クエリと同様[soql_query]ステートメントは 構文を使用して WHERE句のスクリプト式を参照することができます例
String s = Acme for (Account a [select id name from account where name like (s+)]) Your code
次の例ではSOQL クエリのリスト作成と DML updateメソッドを結合します
SOQL クエリから取引先レコードのリストを作成 ListltAccountgt accs = [SELECT Id Name FROM AccountWHERE Name = Siebel]
リストをループして Name 項目を更新 for(Account a accs) aname = Oracle
データベースを更新 update accs
SOQL For ループと標準 SOQL クエリの比較
SOQL forループと SOQL ステートメントはsObjects を取得するために使用するメソッドが異なります「SOQL クエリおよび SOSL クエリ」で説明されている標準クエリはクエリの countまたは多くのオブジェクトレコードを取得できますがSOQL forループはForcecom Web サービス API の queryメソッドおよびqueryMoreメソッドへのコールによる効果的なチャンクを使用してすべての sObject を取得します開発者は常に SOQL forループを使用して多くのレコードを返すクエリ結果を処理しヒープサイズの制限を回避します
集計関数を含むクエリではqueryMoreをサポートしませんforループの 2000 を超える行を返す集計関数を含むクエリーを使用する場合ランタイムの例外エラーが発生します
SOQL For ループの形式
SOQL forループは単一の sObject 変数を使用して一度に 1 件のレコードをsObject リストを使用して 200 のsObject をバッチで処理できます
bull 単一の sObject 形式は forループの ltcode_blockgtを sObject レコードごとに 1 回ずつ実行しますその結果理解および使用が容易ですがforループの本文内でデータ操作言語 (DML) ステートメントを使用する場合効果が大幅に減少しますDML ステートメントは一度に 1 つの sObject のみの処理を終了します
bull sObject リスト形式は forループの ltcode_blockgtを 200 件の sObject リストごとに 1 回ずつ実行しますその結果理解および使用がやや難しくなりますがforループの本文内でDML ステートメントを使用する必要がある場合最適な選択となりますDML ステートメントはsObject のリストを一括処理します
言語構造 Version 180 | For ループ | 54
たとえば次のコードは 2 種類の SOQL クエリ forループ間の差異を示します
データをデータベースにコミットできないため savepoint を作成します Savepoint sp =DatabasesetSavepoint()
insert new account[]new account(name = yyy) new account(name = yyy) new account(name= yyy)
単一の sObject 形式は返されたレコードごとに for ループを一度ずつ実行 Integer I = 0 for (accounttmp [select id from account where name = yyy]) i++ Systemassert(i == 3) デー
タベースに「yyy」という取引先が 3 つあるため ループを 3 回実行
sObject リスト形式を返されたレコードのバッチごとにループを一度ずつ 実行します i = 0 Integer jfor (account[] tmp [select id from account where name = yyy]) j = tmpsize() i++ Systemassert(j == 3) リストには「yyy」という名前の取引先が 3 件 含まれていますSystemassert(i == 1) 1 つのバッチには最大 100 件のレコードを含むことができ 2 件のレコードのみを返すことができ ループは 1 回だけ実行できます
データベースを元の状態に戻します Databaserollback(sp)
メモ
bull breakキーワードと continueキーワードはどちらのインラインクエリ forループ形式でも使用できますsObject リスト形式を使用するとcontinueはsObjects の次のリストにスキップします
bull DML ステートメントは一度に最大 1000 件のレコードを処理できsObject リスト forループは 200件のレコードを一括処理しますその結果sObject リストforループの返されたレコードごとに複数のレコードを挿入更新または削除する場合ランタイム制限エラーが発生する場合があります詳細は「実行ガバナーと制限の理解」を参照してください
SOQL および SOSL クエリ
ステートメントを大かっこで囲むことによってApex の Salesforcecom オブジェクトクエリ言語 (SOQL) またはSalesforcecom オブジェクト検索言語 (SOSL) ステートメントを評価することができます
SOQL ステートメント
SOQL ステートメントはsObjects のリスト単一 sObjectまたは countメソッドクエリの Integer を評価します
たとえばAcme という取引先のリストを取得できます
ListltAccountgt aa = [select id name from account where name = Acme]
このリストからは各要素にアクセスできます
if (aaisEmpty()) Execute commands
言語構造 Version 180 | SOQL および SOSL クエリ | 55
既存のオブジェクトの SOQL クエリから新しいオブジェクトを作成することもできます次の例では従業員数が 10 人より多い最初の取引先の新しい取引先担当者を作成します
Contact c = new Contact(account = [select name from account where NumberofEmployees gt 10limit 1]) cFirstName = James cLastName = Yoyce
新規作成したオブジェクトにはこの項目の Null 値を含みます設定する必要はありません
countメソッドを使用してクエリによって返される行数を返すことができます次の例では姓が Weissmanの取引先担当者数の合計を返します
Integer i = [select count() from contact where lastname = Weissman]
標準の計算を使用して結果に操作することもできます
Integer j = 5 [select count() from account]
SOQL クエリ構文の説明については『Forcecom Web Services API Developers Guide』の「 Salesforcecom オブジェクトクエリ言語 (SOQL)」を参照してください
SOSL ステートメント
SOSL はそれぞれの sObject 型が含まれているsObject のリストのリストとして評価します結果リストは必ずSOSL クエリで指定された順序で返されますSOSL クエリはApex クラスおよび特定ブロックでのみサポートされますトリガで SOSL を使用することはできませんSOSL クエリが指定された sObject 型のレコードを返さない場合検索結果にはその対応する sObject の空のリストが返されます
たとえばフレーズマップで始まる取引先取引先担当者商談およびリードのリストを返します
ListltListltSObjectgtgt searchList = [FIND map IN ALL FIELDS RETURNING Account (id name)Contact Opportunity Lead]
メモ
Apex の FIND句の構文はForcecom Web サービス API の FIND句と異なります
bull Apex の場合FIND句の値は単一引用符で区画されます例
FIND map IN ALL FIELDS RETURNING Account (id name) Contact OpportunityLead
bull Forcecom API の場合FIND句の値は中かっこで区画されます例
FIND map IN ALL FIELDS RETURNING Account (id name) Contact OpportunityLead
searchListから返される各オブジェクトの配列を作成できます
Account [] accounts = ((ListltAccountgt)searchList[0]) Contact [] contacts =((ListltContactgt)searchList[1]) Opportunity [] opportunities =((ListltOpportunitygt)searchList[2]) Lead [] leads = ((ListltLeadgt)searchList[3])
言語構造 Version 180 | SOQL および SOSL クエリ | 56
SOSL クエリ構文の説明については『Forcecom Web Services API Developers Guide』の「 Salesforcecom オブジェクト検索言語 (SOSL)」を参照してください
SOQL および SOSL クエリ結果の処理SOQL クエリおよび SOSL クエリは元のクエリで選択された sObject 項目のデータのみを返しますSOQL クエリまたは SOSL クエリで選択されていない項目にアクセスしようとする場合 (ID 以外)データベースの項目に値が含まれている場合でもランタイムエラーが発生します次のコード例ではランタイムエラーが発生します
insert new Account(name = Singha) Account acc = [select id from account where name =Singha limit 1] Note that name is not selected String name = [select id from accountwhere name = Singha limit 1]name
次のコード例はランタイムエラーが発生しないように書き換えられていますnameがidの後にselect ステートメントの一部として追加されています
insert new Account(name = Singha) Account acc = [select id from account where name =Singha limit 1] Note that name is now selected String name = [select id name fromaccount where name = Singha limit 1]name
つのsObjectを必要とする場合でもSOQLクエリまたはSOSLクエリは必ずすべてのデータを返しますその結果特定の項目にアクセスするためには項目に対する参照を解決する必要がありますたとえばこのコードはSOQL クエリでデータベースから sObject リストを取得しリスト内の最初の取引先レコードにアクセスしレコードの annualRevenue項目の参照を解決します
Double rev = [select annualRevenue from account where name = Acme][0]annualRevenue
SOQL クエリの 1 つの結果だけが返される場合リストの索引に 含める必要はありませんDouble rev2 =[select annualRevenue from account where name = Acme]annualRevenue
SOQL クエリの結果で sObject 項目の参照を解決する必要がないのはクエリがcount演算子の結果として Integerを返す場合のみです
Integer i = [select count() from account]
SOSL クエリで返されるレコードの項目は必ず参照解決する必要があります
数式を含む sObject 項目はSOQL クエリまたはSOSL クエリが発行されたときに項目の値を返します数式内で使用されているその他の項目に対する変更はレコードが Apex に保存しおよび再び問い合わせされるまで数式項目の値に反映されませんその他の読み取り専用 sObject 項目と同様数式項目の値自体をApexで変更することはできません
SOQL 集計関数の使用SUM()や MAX()などSOQL の集計関数を使用して分析のクエリーでデータをロールアップおよび集計できます集計関数の詳細は『Forcecom Web Services API Developers Guide』の「集計関数」を参照してください
集計関数はGROUP BY句がなくても使用できますたとえばAVG()集計関数を使用してすべての商談の平均金額が分かります
AggregateResult[] groupedResults = [SELECT AVG(Amount)aver FROM Opportunity] Object avgAmount= groupedResults[0]get(aver)
言語構造 Version 180 | SOQL および SOSL クエリ結果の処理 | 57
集計関数を含むクエリーはAggregateResult オブジェクトの配列で結果を返しますAggregateResult は参照専用sObject でクエリ結果にのみ使用されます
集計関数はGROUP BY句とともに使用する場合にレポートを生成するより強力なツールとなりますたとえばキャンペーンにごとにすべての商談の平均金額が分かります
AggregateResult[] groupedResults = [SELECT CampaignId AVG(Amount) FROM Opportunity GROUPBY CampaignId] for (AggregateResult ar groupedResults) Systemdebug(Campaign ID +arget(CampaignId)) Systemdebug(Average amount + arget(expr0))
別名のない SELECTリストの集計項目は形式が expriの暗黙的別名を自動的に取得しますiは明示的な別名のない集計項目の順序を示しますiの値は 0 から始まり明示的な別名のない集計項目ごとに増えます詳細は『Forcecom Web Services API Developers Guide』の「GROUP BYでの別名の使用」を参照してください
非常に大きな SOQL クエリの処理SOQLクエリヒープサイズの制限を超える多くの sObjects を返しエラーが発生する場合があります問題を解決するには代わりに SOQL クエリ forループを使用しますqueryおよび queryMoreへの内部コールの使用によりレコードの複数の一括処理が可能になります
たとえば結果が大きすぎる場合次の構文でランタイム例外が発生します
Account[] accts = [SELECT id FROM account]
代わりに次の例のいずれかで SOQL クエリの forを使用します
for ループ内で DML ステートメントを実行しない場合は この形式を使用します (Account a [SELECTid name FROM account WHERE name LIKE Acme]) ここに DML ステートメントのないコード
for ループ内で DML ステートメントを実行している場合 この形式を使用 (ListltAccountgt accts [SELECT id name FROM account WHERE name LIKE Acme]) ここに更新取引先のコード
次の例はレコードの一括更新に使用する SOQL クエリ forループを示しますすべてのレコードの取引先担当者の姓を変更するとします
public void massUpdate() for (ListltContactgt contacts [Select FirstName LastName FromContact]) for(Contact c contacts) if (cFirstName == Barbara ampamp cLastName ==Gordon) cLastName = Wayne update contacts
メモ forループで SOQL クエリを使用する代わりにApex の一括処理を使用してレコードを一括更新するとガバナ制限に達するリスクが最小限に抑えられます
より効果的なSOQLクエリとして特にトリガ内のクエリについてはセレクティブ (索引付き) クエリを使用しますセレクティブクエリとはプライマリキー外部キー名前監査日付項目(LastModifiedDateなど)または外部ID項目で絞り込みを行うクエリを指します大規模な組織ではセレクティブではないクエリを実行時に停止して長時間にわたる操作時間を短縮できますアプリケーションで必要な場合salesforcecomの担当者にお問い合わせください
詳細は「SOQL For ループ」 (ページ 54)を参照してください
言語構造 Version 180 | 非常に大きな SOQL クエリの処理 | 58
1 つのレコードを返す SOQL クエリ結果リストに 1 つだけ要素が含まれている場合SOQL クエリを使用して単一の sObject 値を割り当てることができます式の L 値が単一の sObject 型である場合Apex は自動的にクエリ結果リスト内の 1 つの sObjectレコードを L 値に割り当てますリスト内に sObjects がないまたは複数の sObject がある場合ランタイム例外が発生します例
ListltAccountgt accts = [SELECT id FROM account]
クエリから 1 つの行が返される場合にのみコードのこれらの行が 有効です中間 sObject 変数に割り当てられていない場合2 番目の行は項目の クエリからの参照を解決しますAccount acct = [SELECT id FROMaccount] String name = [SELECT name FROM account]name
外部キーおよび親子関係の SOQL クエリについてSOQL クエリのSELECTステートメントは外部キー親子レコードの結合など有効な SOQL ステートメントとなります外部キーの結合が含まれている場合生成される sObjects は通常の項目表記によって参照できます例
Systemdebug([SELECT accountname FROM contact WHERE firstname = Caroline]accountname)
またsObjects の親子関係は SOQL クエリとして動作します例
for (Account a [SELECT id name (SELECT lastname FROM contacts) FROM account WHERE name= Acme]) Contact[] cons = acontacts
連絡先を 1 件のみに制限しているため次の例も有効です (Account a [SELECT id name (SELECT lastnameFROM contacts limit 1) FROM account WHERE name = testAgg]) Contact c = acontacts
SOQL クエリおよび SOSL クエリでのApex 変数の使用Apex のSOQL ステートメントおよび SOSL ステートメントは先にセミコロン () がある場合Apex スクリプト変数と式を参照することができますSOQL ステートメントまたは SOSL ステートメント内でローカルスクリプト変数を使用することはバインドと呼ばれますApex パーサーはSOQL ステートメントまたは SOSL ステートメントを実行する前にまずスクリプトコンテキスト内のローカル変数を評価しますバインド式は次のものとして使用できます
bull FIND句の検索文字列bull WHERE句の条件リテラルbull LIMIT句の数値bull WHERE句の IN演算子または NOT IN演算子値の動的セットを絞り込むことができますいかなるデータ型
のリストも処理しますがID または String のリストで特に使用されますbull FIND句の区分名
例
Account A = new Account(name=xxx) insert A Account B
簡単なバインド B = [select id from account where id = Aid]
言語構造 Version 180 | 1 つのレコードを返す SOQL クエリ | 59
計算によるバインド B = [select id from account where name = (x + xx)]
String s = XXX
式によるバインド B = [select id from account where name = XXXXsubstring(03)]
クエリの結果である式によるバインド B = [select id from account where name = [select name fromaccount where id = Aid]name]
Contact C = new Contact(lastName=xxx accountid=Aid) insert new Contact[]C newContact(lastName=yyy accountId=Aid)
親クエリおよび集合クエリのバインド B = [select id (select id from contacts where id = Cid)from account where id = Aid]
返される連絡先 Contact D = Bcontacts
制限バインド Integer i = 1 B = [select id from account limit i]
ID リストによる IN バインドsObjects のリスト もし用できますオブジェクトの ID がバインドに 使用されます Contact[] cc = [select id from contact limit 2] Task[] tt = [select id fromtask where whoId in cc]
String リストによる IN バインド String[] ss = new String[]a b Account[] aa = [selectid from account where accountnumber in ss]
すべての句のバインドを含む SOSL クエリ
String myString1 = aaa String myString2 = bbb Integer myInt3 = 11 String myString4= ccc Integer myInt5 = 22
ListltListltSObjectgtgt searchList = [FIND myString1 IN ALL FIELDS RETURNING Account (id nameWHERE name LIKE myString2 LIMIT myInt3) Contact Opportunity Lead WITH DIVISION=myString4 LIMIT myInt5]
SOQL ステートメントによるすべてのレコードの問い合わせSOQL ステートメントはALL ROWSキーワードを使用して削除されたレコードアーカイブされたアクティビティなど組織内のすべてのレコードを問い合わせることができます例
SystemassertEquals(2 [SELECT count() FROM contact WHERE accountid = aid ALL ROWS])
ALL ROWSを使用して組織のゴミ箱の中にあるレコードを問い合わせすることができますALL ROWSキーワードは FOR UPDATEキーワードとともに使用することはできません
ロックするステートメント
Apex を使用するとsObject レコードをロックできますレコードを更新してレース条件およびスレッドの安全性の問題を回避しますsObject レコードがロックされるとその他のプログラムまたはユーザーを更新できません
言語構造 Version 180 | SOQL ステートメントによるすべてのレコードの問い合わせ | 60
Apex の一連の sObject レコードをロックするにはインライン SOQL ステートメントの後に FOR UPDATEを埋め込みますたとえば次のステートメントでは2 つの取引先に問い合わせするほか返される取引先をロックします
Account [] accts = [select id from Account limit 2 for update]
メモ ロックを使用する SOQL クエリではORDER BYキーワードを使用できませんただしクエリ結果は自動的に ID によって並べ替えられます
このコールで取引先がロックされるとデータ操作言語 (DML) ステートメントがトランザクションのデータベースの項目値を変更できます
警告 Apex スクリプトにロックを設定する場合は慎重に使用してください詳細は以下の 「デッドロックの回避」を参照してください
SOQL For ループのロックFOR UPDATEキーワードも SOQL forループ内で使用できます例
for (Account[] accts [select id from Account for update]) Your code
SOQL For ループ (ページ 54) で説明しているように上記の例は Forcecom Web サービス API の query()メソッドおよび queryMore()メソッドのコールに内部的に対応しています
commitステートメントはありませんApexスクリプトが正常に完了するとデータベースへのすべての変更は自動的にコミットされますApex スクリプトが正常に完了しない場合データベースへのすべての変更はロールバックされます
デッドロックの回避Apex はデッドロックの可能性があり複数のデータベース表または行へのアップデートを呼び出すその他の手続き型ロジック言語にもその可能性がありますこうしたデッドロックを回避するためにApex ランタイムエンジンは次のことを行います
1 sObject 親レコードを最初にその後子レコードをロックする2 同じデータ型の複数レコードを編集する場合sObject レコードを ID 順にロックする
開発者は行をロックしてデッドロックが行われないようにする場合慎重に使用してくださいアプリケーション内のすべての場所から表および行に同じ順序でアクセスして標準デッドロック回避方法を使用していることを確認してください
トランザクションの制御
すべてのトランザクションはApex スクリプトを実行するトリガWeb サービスVisualforce ページまたは匿名ブロックによって制御されていますApex スクリプトが正常に完了するとすべての変更がデータベースにコミットされますApex スクリプトが正常に完了しない場合データベースへのすべての変更はロールバックされます
言語構造 Version 180 | SOQL For ループのロック | 61
ただしレコードの処理時にビジネスルールでは処理を別の指示で続行できるよう部分的な作業 (すでに実行された DML ステートメント) の「ロールバック」が必要な場合がありますApexを使用するとsavepointつまりその時間のデータベースの状態を指定するトランザクションのポイントを生成できますsavepoint の後に発生する DML ステートメントは破棄することができsavepoint を生成した時点と同じ状況にデータベースを復元できます
次の制限事項はsavepoint 変数の生成およびデータベースのロールバックに適用されます
bull 複数の savepoint を設定しかつ生成した最後の savepoint でない savepoint にロールバックすると後の savepoint変数が無効となりますたとえば最初にsavepoint SP1を生成次にsavepoint SP2を生成したとしてSP1にロールバックすると変数 SP2は無効となりますこの際SP2 を使用しようとするとランタイムエラーが発生します
bull savepoints への参照は各トリガ呼び出しが新しい実行コンテクストであるため複数のトリガと共有することはできません静的変数として savepoint を宣言しトリガコンテキスト全体で使用しようとする場合ランタイムエラーが発生します
bull すべてのコンテキストでつまりトリガ匿名ブロックWSDL メソッドまたはユニットテストで 5 つのsavepoint のみを設定できます追加の savepoint を設定しようとするとランタイムエラーが発生します
bull rollbackによるデータベースの復元はすべてのコンテキストでつまりトリガ匿名ブロックWSDLメソッドまたはユニットテストで20回まで実行できますそれ以上の回数をロールバックしようとするとランタイムエラーが発生します
次はsetSavepointおよび rollbackデータベースメソッドの使用例です
Account a = new account(name = xxx) insert a
SystemassertEquals(null [select accountnumber from account where id = aid]accountnumber)
accountNumber が null の場合に savepoint を作成します
Savepoint sp = DatabasesetSavepoint()
取引先意番号を変更します
aaccountnumber = 123
update a
SystemassertEquals(123 [select accountnumber from account where id = aid]accountnumber)
以前の null 値にロールバックします
Databaserollback(sp)
SystemassertEquals(null [select accountnumber from account where id = aid]accountnumber)
例外ステートメント
Apex では例外を使用してエラーまたはスクリプト実行の正常な流れを中断するイベントを処理することができますthrowステートメントを使用して例外を生成しtrycatchおよび finallyを使用して例外から適切に回復することができます
言語構造 Version 180 | 例外ステートメント | 62
例外クラスを使用して独自の例外を作成することもできます詳細は「例外クラス」 (ページ 315)を参照してください
Throw ステートメントthrowステートメントを使用して例外を明示的に発生することができます例外を投げるにはthrowステートメントを使用して例外オブジェクトを作成し特定のエラーに関する情報を提供します例
throw exceptionObject
Try-Catch-Finally ステートメントtrycatchfinallyステートメントを使用して投げられた例外から適切に回復することができます
bull tryステートメントは例外が発生するコードのブロックを識別しますbull catchステートメントは特定の種類の例外を処理できるコードのブロックを識別します単一のtryブロッ
クに対して複数の catchステートメントを使用できますが各 catchステートメントには一意の例外タイプがなければなりません
bull オプションでfinallyステートメントは実行が保証されているコードをブロックを識別しtryブロック内のコードの後でクリーンアップすることができます単一の tryステートメントには関連する finally
ステートメントを 1 つだけ含むことができます
構文
これらのステートメントの構文は次のとおりです
try code_block catch (exceptionType) code_block その他の例外タイプのオプションの catchステートメント 一般的な例外タイプ「Exception」 は使用時に最後の catch ブロックでなければなりま
せん catch (Exception e) code_block オプションの finally ステートメント finally code_block
例
例
try ここにコード catch (ListException e) リスト例外処理コード catch (Exception e) 汎用例外処理コード
メモ 実行ガバナーによる制限の例外を取得できません詳細は「実行ガバナーと制限の理解」を参照してください
言語構造 Version 180 | Throw ステートメント | 63
第 3 章
Apex の呼び出し
次のメカニズムでApex スクリプトを呼び出すことができますトピック
bull トリガbull トリガbull Apex スケジューラ (Apex クラスのみ)bull Apex スケジューラbull 匿名ブロックbull 匿名ブロックbull AJAX Toolkitbull AJAX での Apex
トリガ
Apex スクリプトはトリガを使用して呼び出しますトリガは次の操作の前後に実行する Apex スクリプトです
bull insertbull updatebull deletebull mergebull upsertbull undelete
たとえばオブジェクトのレコードがデータベースに挿入される前レコードが削除された後またはレコードがごみ箱から復元した後に実行されるトリガがある場合があります
連絡先または取引先などの最上位の標準オブジェクトにトリガを定義することができますがContactRole など標準子オブジェクトには定義できません
bull ケースコメントの場合は[設定] [ケース] [ケースコメント] [トリガ] をクリックしますbull 電子メールメッセージの場合は[設定] [ケース] [電子メールメッセージ] [トリガ]をクリックします
トリガは次の 2 つの種類に分けられます
bull Beforeトリガを使用してデータベースが保存される前にレコード値を更新または検証することができますbull After トリガを使用してデータベースで設定された項目値(レコードの Id項目または lastUpdated項目な
ど)にアクセス監査表にログキューによって非同期イベントを発生するなどそのほかのレコードの変更に影響を与えたりすることができます
トリガは最初にトリガを発生したレコードと同じデータ型の別のレコードを変更することもできますたとえば連絡先 Aが更新された後でトリガが発生する場合トリガは連絡先 BCおよび Dを変更することもできますトリガの利用により他のレコードを変更できまたこれらの変更によってより多くのトリガが発生しうるためにApex ランタイムエンジンは一連の処理を監視し無限に繰り返されることないように実行回数の制限を設定します詳細は「実行ガバナーと制限の理解」を参照してください
またトリガを発生したレコードに対してbeforeトリガで更新または削除するかまたはafterトリガで削除しようとするとランタイムエラーが発生しますこれは直接の操作および間接的な操作が含まれますたとえば取引先 Aを更新し取引先 Aの before update トリガが連絡先 Bを挿入連絡先 Bの after insert トリガが取引先 Aを問い合わせDML updateステートメントまたはデータベースメソッドを使用してそれを更新するとbefore トリガで取引先 Aが間接的に更新されランタイムエラーが発生します
実装時の検討事項
トリガを作成する前は次の点に注意してください
bull upsertトリガは必要に応じて before および after の insertトリガまたは before および after の updateトリガを発生します
bull mergeトリガは削除されるレコードには before および after の deleteトリガがまた更新されるレコードにはbefore および after の updateトリガのみが発生します「トリガと Merge ステートメント」 (ページ 73)を参照してください
Apex の呼び出し Version 180 | トリガ | 65
bull レコードが復元された後に実行するトリガは特定のオブジェクトでのみ動作します「トリガと復元レコード」 (ページ 73)を参照してください
bull トリガが終わるまで項目履歴は記録されませんトリガから項目履歴を問い合わせても現在のトランザクションの履歴は表示されません
bull API の一括処理を想定するトリガは記述しないでくださいAPI の一括処理を指定した大きさより小さいセットに分割する場合があります
バルクトリガ以前のバージョンのApexではトリガが一度に処理できるのは 1 つの sObject だけで一括処理はできませんでしたそのためデータベースクエリの制限を超えずにSOQLクエリまたはDMLステートメントを含むトリガを実行できるsObjectに対する API 一括処理を利用することができませんでした
このバージョンの Apex では単一レコード処理モデルは使用することができませんデフォルトではすべてのトリガがバルクトリガで複数のレコードを一度に処理できます
メモ 定期的な行動の insertdeleteまたは updateのトリガは一括で処理することができません
バルクトリガは単一のレコード更新と次のような一括処理に対応できます
bull データインポートbull バルク Forcecom API コールbull レコード所有者の変更や削除などの一括操作bull 再帰 Apex メソッドやバルク DML ステートメントを呼び出すトリガ
トリガ構文トリガを定義するには次の構文を使用します
trigger triggerName on ObjectName (trigger_events) code_block
trigger_eventsには次のイベントを 1 つ以上含むカンマ区切りのリストを指定できます
bull before insert
bull before update
bull before delete
bull after insert
bull after update
bull after delete
bull after undelete
メモ
bull webServiceキーワードをトリガで使用できるのはメソッドで非同期として定義されている場合つまりメソッドが futureキーワードで定義されている場合のみです
bull 定期的な行動または定期的な ToDo の insertdeleteまたは updateによって呼び出されるトリガはForcecom API からトリガが大量に呼び出されるときランタイムエラーになります
Apex の呼び出し Version 180 | バルクトリガ | 66
たとえば次のコードは取引先オブジェクトで before insertイベントおよび before updateイベントのトリガを定義します
trigger myAccountTrigger on Account (before insert before update) ここにコードを入力
トリガのコードブロックにstaticキーワードを指定することはできませんトリガには内部クラスに適用できるキーワードのみを含めることができますまたトリガが行ったデータベースへの変更は手動でコミットする必要はありませんApex スクリプトが正常に完了するとデータベースへのすべての変更は自動的にコミットされますApex スクリプトが正常に完了しない場合データベースへのすべての変更はロールバックされます
トリガコンテキスト変数すべてのトリガは開発者がランタイムコンテキストにアクセスできるようにする暗黙的な変数を定義しますこれらの変数はSystemTriggerクラスに含まれています
使用方法変数
Apex スクリプトの現在のコンテキストがVisualforce ページWeb サービスまたは executeanonymous() API コールでなくトリガである場合真を返します
isExecuting
Salesforcecom ユーザインターフェースApexまたは API から insert 操作によりトリガが起動した場合真を返します
isInsert
Salesforcecom ユーザインターフェースApexまたは API から upsert 操作によりトリガが起動した場合真を返します
isUpdate
Salesforcecom ユーザインターフェースApexまたは API から delete 操作によりトリガが起動した場合真を返します
isDelete
このトリガがレコードが保存される前に発生した場合真を返しますisBefore
このトリガがすべてのレコードが保存された後に発生した場合真を返しますisAfter
レコードがごみが子から復元した後 (SalesforcecomユーザインターフェースApexまたは API からの undelete 操作の後) トリガが起動した場合真を返します
isUndelete
新しいバージョンの sObject レコードのリストを返します
この sObject リストはinsertトリガおよびupdateトリガでのみ使用できレコードは beforeトリガでのみ更新できます
new
新しいバージョンの sObject レコードへの ID のマップです
このマップは before updateトリガafter insertトリガafter updateトリガでのみ使用できます
newMap
古いバージョンの sObject レコードのリストを返します
この sObject リストは updateトリガdeleteトリガでのみ使用できます
old
古いバージョンの sObject レコードへの ID のマップです
このマップは updateトリガdeleteトリガでのみ使用できます
oldMap
Apex の呼び出し Version 180 | トリガコンテキスト変数 | 67
使用方法変数
トリガ呼び出しでの古いバージョン新しいバージョン両方のレコードの合計数size
メモ トリガが発生するレコードに無効な項目値がある場合 (たとえば0 で割る数式など)値は newnewMapoldおよび oldMapのトリガコンテキスト変数で nullに設定されます
たとえばこの簡単なトリガの場合Triggernewは sObjects のリストでforループで反復したりSOQLクエリの IN句でバインド変数として使用できます
Trigger t on Account (after insert) for (Account a Triggernew) 各 sObject で反復
この単一のクエリはトリガしている取引先のいずれかと関連する各連絡先を 検索しますTriggernew はレコードのコレクションですが SOQL クエリのバインド変数として使用されている場合Apex は自動的に レコードのリストを対応する ID のリストに変換しますContact[] cons = [select lastname from contactwhere accountid in Triggernew]
このトリガではTriggerisBeforeおよびTriggerisDeleteのような Boolean コンテキスト変数を使用し特定のトリガ条件にのみ実行するコードを定義します
trigger myAccountTrigger on Account(before delete before insert before update afterdelete after insert after update) if (TriggerisBefore) if (TriggerisDelete)
before delete トリガの場合トリガは Triggerold リストで削除されるレコードに アクセスしますfor (Account a Triggerold) if (aname = okToDelete) aaddError(You cant deletethis record) else
before insert トリガまたは before update トリガの場合Triggernew で新しいレコードに アクセスします for (Account a Triggernew) if (aname == bad) anameaddError(Bad name) if (TriggerisInsert) for (Account a Triggernew) SystemassertEquals(xxxaaccountNumber) SystemassertEquals(industry aindustry) SystemassertEquals(100anumberofemployees) SystemassertEquals(1000 aannualrevenue) aaccountNumber = yyy
トリガが before トリガでない場合after トリガである必要があります else if (TriggerisInsert) ListltContactgt contacts = new Contact[0] for (Account a Triggernew) if(aname ==makeContact) contactsadd(new Contact (lastname = aname accountId = aid)) insertcontacts
コンテキスト変数の考慮事項トリガコンテキスト変数については次の考慮事項について注意してください
bull triggernewおよび triggeroldをApex DML 操作で使用することはできませんbull triggernewのオブジェクトを使用して項目の値を変更することができますがbefore トリガでのみ行えま
すすべての after トリガでtriggernewは保存されずランタイム例外が投げられますbull triggeroldは常に読み取り専用ですbull triggernewを削除することはできません
次の表ではさまざまなトリガイベントの特定の操作についての考慮事項を示しています
Apex の呼び出し Version 180 | コンテキスト変数の考慮事項 | 68
削除 DML 操作を使用した元のオブジェクトの削除
更新 DML 操作を使用した元のオブジェクトの更新
triggernewを使用した項目の変更
トリガイベント
該当なし元のオブジェクトが作成されていません
該当なし元のオブジェクトが作成されていません
可before insert
参照できるものがないため更新できません
参照できるものがないため更新できません
可能ですが必須ではありません挿入後すぐにオブジェクトが削除されます
可不可triggernewがすでに保存されているためランタイムエラーが発生します
after insert
不可ランタイムエラーが発生します
不可ランタイムエラーが発生します
可before update
可更新はオブジェクトが削除される前に保存される
可正しくないスクリプトにより無限ループが発生し
不可triggernewがすでに保存されているため
更新後
のでオブジェクトが復元た場合はガバナー制限にランタイムエラーが発生します された時に更新結果を表示
することができますよりエラーが検出されます
不可ランタイムエラーが発生します削除はすでに処理中です
可更新はオブジェクトが削除される前に保存されるのでオブジェクトが復元された時に更新結果を表示することができます
不可ランタイムエラーが発生しますtriggernew
は before delete トリガで使用できません
before delete
該当なしオブジェクトはすでに削除されています
該当なしオブジェクトはすでに削除されています
不可ランタイムエラーが発生しますtriggernew
は after delete トリガで使用できません
after delete
可能ですが必須ではありません挿入後すぐにオブジェクトが削除されます
可不可ランタイムエラーが発生しますtriggernew
は after undelete トリガで使用できません
after undelete
一般的なバルクトリガイディオムバルクトリガを使用すると開発者は実行ガバナー制限を超えることなくより多くのレコードを処理することができますが複数のレコードのバッチを一度に呼び出すため開発者は理解したりコード化することが難しくなる場合があります次の項では一括して記述する場合に頻繁に使用されるイディオムの例について説明します
バルクトリガでのマップおよびセットの使用
セットおよびマップのデータ構造はバルクトリガの正常なコード化において重要ですセットを使用して各レコードを分割しマップを使用してレコード ID で編成されたクエリ結果を保持することができます
Apex の呼び出し Version 180 | 一般的なバルクトリガイディオム | 69
たとえばサンプルの見積アプリケーションのバルクトリガはまず Triggernewの OpportunityLineItem レコードに関連する各価格表のエントリをセットに追加しセットに個別の要素が含まれるようにしますそして関連する製品の色の PricebookEntries を問い合わせマップ内に結果を投入しますマップが作成されるとトリガは Triggernewの OpportunityLineItems で反復しマップを使用して適切な色を割り当てます
新しい品目は商談に追加されるとこのトリガは関連する製品の色の値を 新しいレコードにコピーしますtrigger oppLineTrigger on OpportunityLineItem (before insert)
各 OpportunityLineItem レコードの場合関連する価格表のエントリを セットに追加し重複はなくなりますSetltIdgt pbeIds = new SetltIdgt() for (OpportunityLineItem oli Triggernew)pbeIdsadd(olipricebookentryid)
そして関連する製品の色の PricebookEntries を問い合わせマップ内に 結果を投入しますMapltIdPricebookEntrygt entries = new MapltId PricebookEntrygt( [select product2color__c frompricebookentry where id in pbeIds])
マップを使用してトリガに処理される各 OpportunityLineItem の適切な色を 設定します for(OpportunityLineItem oli Triggernew) olicolor__c =entriesget(olipricebookEntryId)product2color__c
バルクトリガのレコードとクエリ結果の相関
TriggernewMapおよび TriggeroldMapの ID-to-sObject マップを使用してレコードをクエリ結果に相関させますたとえばサンプル見積アプリケーションのこのトリガではTriggeroldMapを使用して一意のID のセットを作成します (TriggeroldMapkeySet())セットはクエリの一部として使用されトリガで処理される商談に関連する見積のリストを作成しますクエリに返される各見積の場合関連する商談がTriggeroldMapから取得され削除されないようにします
trigger oppTrigger on Opportunity (before delete) for (Quote__c q [select opportunity__cfrom quote__c where opportunity__c in TriggeroldMapkeySet()]) TriggeroldMapget(qopportunity__c)addError(Cannot delete opportunity with a quote)
トリガを使用した一意の項目を持つレコードの挿入または更新
insertイベントまたは upsertイベントによってレコードがバッチ内の別の新しいレコードで一意の項目の値を複製する場合重複したレコードについてのエラーメッセージには最初のレコードの ID が記載されますただし要求が完了するまではエラーメッセージが適切でない場合があります
トリガがある場合一括操作のリトライロジックによりロールバックリトライサイクルが発生しますそのリトライサイクルは新しいキーを新しいレコードに割り当てますたとえば2 つのレコードに一意の項目の同じ値が挿入されinsertイベントがトリガに定義されている場合2 番目の重複レコードが失敗し最初のレコードの ID が報告されますただし変更がロールバックし最初のレコードが再挿入されるとレコードは新しい ID を受け取りますつまり2 番目のレコードで報告されるエラーメッセージは有効ではありません
トリガの定義トリガスクリプトは関連するオブジェクトの下にメタデータとして保存されますSalesforcecomでトリガを定義する手順は次のとおりです
1 標準オブジェクトの場合は[設定] [カスタマイズ] をクリックし[トリガ] をクリックします
Apex の呼び出し Version 180 | トリガの定義 | 70
カスタムオブジェクトの場合は[設定] [作成] [オブジェクト] をクリックしオブジェクトの名前をクリックします
キャンペーンメンバーの場合[設定] [カスタマイズ] [キャンペーン] [キャンペーンメンバー] [トリガ] をクリックします
ケースコメントの場合は[設定] [ケース] [ケースコメント] [トリガ] をクリックします
電子メールメッセージの場合は[設定] [ケース] [電子メールメッセージ] [トリガ]をクリックします2 [トリガ] 関連リストで[新規] をクリックします3 [バージョン設定]をクリックしてこのトリガで使用するApexおよびAPIのバージョンを指定します組織
がAppExchangeから管理パッケージをインストールした場合このトリガで使用する各管理パッケージのバージョンも指定できます通常はすべてのバージョンについてデフォルト値を使用してくださいデフォルト値ではApexおよびAPIについても各管理パッケージについてもトリガを最新バージョンに関連付けます最新バージョンのパッケージのものとは異なるコンポーネントや機能にアクセスする場合は管理パッケージの古いバージョンを指定することもできます古いバージョンのApexおよびAPIを指定して特定の動作を維持できます
4 トリガをコンパイルして有効にする必要があれば[有効]チェックボックスをオンにします組織のメタデータにスクリプトを保存するだけならばこのチェックボックスはオフにしておきますこのチェックボックスはデフォルトではオンです
5 [内容]テキストボックスでそのトリガのApexを入力します1 つのトリガは最大 32000文字までです
トリガを定義するには次の構文を使用します
trigger triggerName on ObjectName (trigger_events) code_block
trigger_eventsには次のイベントを 1 つ以上含むカンマ区切りのリストを指定できます
bull before insert
bull before update
bull before delete
bull after insert
bull after update
bull after delete
bull after undelete
メモ
bull webServiceキーワードをトリガで使用できるのはメソッドで非同期として定義されている場合つまりメソッドが futureキーワードで定義されている場合のみです
bull 定期的な行動または定期的な ToDo の insertdeleteまたは updateによって呼び出されるトリガはForcecom API からトリガが大量に呼び出されるときランタイムエラーになります
6 [保存] をクリックします
メモ トリガは最後にコンパイルされて以降依存するメタデータに変更がない限りIsValidフラグを trueに設定して保存しますオブジェクトや項目の説明の編集などの表面的な変更も含めてトリガで使用されているオブジェクト名や項目に変更があるとApex コンパイラがコードを再処理するまでisValidフラグは falseに設定されますトリガが次に実行されときかユーザがトリガをメタデータに再保存するときに再コンパイルされます
Apex の呼び出し Version 180 | トリガの定義 | 71
参照項目が削除済みのレコードを参照している場合参照項目は自動的に null になりApex トリガ入力規則ワークフロールールまたは積み上げ集計項目は実行されません
Apex トリガエディタ
VisualforceまたはApexを編集するときVisualforce開発モードフッターでまたは設定から次の機能を持つエディタを使用できます
構文の強調表示エディタはキーワードとすべての関数および演算子について自動的に構文を強調表示します
検索 ( )
検索により現在のページクラスまたはトリガの中のテキストを検索できます検索を使用するには[検索]テキストボックスに文字列を入力し[次を検索] をクリックします
bull 検出した検索文字列を他の文字列に置き換えるには[置換]テキストボックスに新しい文字列を入力しそのインスタンスだけを置き換える場合は [置換] をクリックしそのインスタンスとそれ以外にそのページクラスまたはトリガに出現する検索文字列のすべてのインスタンスを置き換える場合は[すべて置換] をクリックします
bull 検索操作で大文字小文字を区別するには[大文字と小文字を区別する] オプションをオンにしますbull 検索文字列として正規表現を使用するには[正規表現]オプションをオンにします正規表現はJavaScript
の正規表現規則に従います正規表現を使った検索では折り返しされて複数行になる文字列も検索できます
正規表現で検出した文字列を置換操作で使用する場合検出した検索文字列から得られる正規表現のグループ変数 ($1$2など) をバインドすることもできますたとえばltH1gtタグを ltH2gtタグで置き換え元の ltH1gtの属性はすべてそのままにするにはltH1(s+)()gtを検索しそれを ltH2$1$2gtで置き換えます
指定行に移動 ( )
このボタンにより指定した行番号を強調表示できますその行が現在表示されていない場合はエディタがその行までスクロールします
元に戻す ( ) またはやり直し ( )
[元に戻す] を使用して編集動作を取り消し[やり直し] により元に戻した編集動作をやり直します
フォントサイズドロップダウンリストからフォントサイズを選択しエディタに表示される文字のサイズを制御します
行と列の位置
カーソルの行と列の位置はエディタ下部のステータスバーに表示されますこれは[指定行に移動] ( )とともに使用しエディタ内をすばやく移動できます
行と文字のカウント行と文字の合計数はエディタ下部のステータスバーに表示されます
Apex の呼び出し Version 180 | トリガの定義 | 72
トリガと Merge ステートメント結合処理では独自のトリガイベントは発生しません代わりにdelete イベントおよび update イベントが発生します
削除されるレコードの削除一度の結合操作で削除されるすべてのレコードに対して単一の delete イベントが発生します結合操作の結果として削除されたレコードを指定するにはTriggeroldの MasterRecordId項目を使用します結合操作により削除されるレコードのMasterRecordId項目には更新されるレコードのIDが設定されますMasterRecordId項目は after deleteトリガイベントでのみ設定されますアプリケーションで結合の結果として削除されたレコードに特別な処理が必要な場合after deleteトリガイベントを使用する必要があります
更新されるレコードの処理一度の結合操作では更新されるレコードに対してのみ単一の update イベントが発生します結合操作の結果として再び親となる子レコードではトリガは発生しません
たとえば 2 つの取引先担当者が結合する場合取引先担当者の delete および update トリガが発生します取引先や商談など取引先担当者に関連するレコードのトリガは発生しません
結合が行われる場合次の順にイベントが発生します
1 before deleteトリガが発生します2 結合によって必要なレコードを削除し新しい親レコードを子レコードに割り当て削除されたレコードの
MasterRecordId項目を設定します3 after deleteトリガが発生します4 マスタレコードに必要な特定の更新を実行します通常の更新トリガが適用されます
トリガと復元レコードafter undeleteトリガイベントは復元レコードつまりいったん削除されごみ箱から復元したレコードのみを扱います未削除レコードとも呼ばれます
after undeleteトリガイベントは最上位のオブジェクトのみ実行しますたとえば取引先を削除すると商談も削除されます取引先をごみ箱から復元すると商談も復元されます取引先と商談の両方に関連するafter undeleteトリガイベントがある場合取引先の after undeleteトリガイベントのみを実行します
after undeleteトリガイベントは次のオブジェクトにのみ発生します
bull 取引先bull 納入商品bull キャンペーンbull ケースbull 取引先担当者bull 契約bull カスタムオブジェクトbull イベントbull リードbull 商談
Apex の呼び出し Version 180 | トリガと Merge ステートメント | 73
bull 商品bull ソリューションbull タスク
トリガと実行の順序レコードを insertupdateupsertステートメントを使用して保存すると次のイベントが順番に発生します
メモ サーバ上でこれらのイベントが実行される前にブラウザはレコードに連動選択リスト項目が含まれていることを確認する JavaScript 検証を実行します検証は連動選択リストを使用できる値に制限しますクライアント側では他に検証は行われません
サーバ側では次のことが行われます
1 元のレコードがデータベースからロードまたは insertステートメント用にレコードを初期化します2 要求により新しいレコード項目の値がロードされ古い値を上書きします要求が標準 UI 編集ページから行
われた場合次の点についてレコードを確認するシステム検証を実行します
bull レイアウト固有のルールの準拠bull レイアウトレベルおよび項目定義レベルで必要な値bull 有効な項目形式bull 最大項目長
Apex アプリケーションまたは Web サービス API コールなど他のソースから要求が行われた場合この段階でシステム検証は実行されません
3 すべての beforeトリガを実行します4 すべての必須項目にnull以外の値があることを検証しユーザー定義の入力規則を実行するなどシステム
検証がもう一度行われます2回目の検証が行われない場合の唯一のシステム検証 (標準 UI 編集ページから要求が行われた場合) はレイアウト固有のルールの適用となります
5 レコードはデータベースに保存されますがコミットはされません6 すべての afterトリガを実行します7 割り当てルールを実行します8 自動レスポンスルールを実行します9 ワークフロールールを実行します10 ワークフローの項目自動更新がある場合レコードを再度更新します11 レコードがワークフローの項目自動更新により更新された場合beforeトリガおよびafterトリガを再度(し
かし一度きり) 発生します
メモ 更新する必要がある場合にのみbeforeトリガおよび afterトリガが複数回発生します項目が既に値に設定されている場合トリガは再度発生しません
12 エスカレーションルールを実行します13 レコードにロールアップ集計項目が含まれる場合またはオブジェクト間ワークフローの一部である場合
計算を実行し親レコードのロールアップ集計項目を更新します14 すべての DML 操作がデータベースにコミットされます15 電子メール送信などコミット後のロジックが実行されます
Apex の呼び出し Version 180 | トリガと実行の順序 | 74
メモ 組織のワークフロールールおよび積み上げ集計項目の評価という重要な更新が有効である場合再帰保存時のステップ 7 から 13 をスキップします Salesforcecom オンラインヘルプの「Spring 09 ワークフロールールおよび積み上げ集計項目の評価の更新とは」を参照してください
その他の考慮事項
トリガを使用する場合次の点に注意してください
bull [リードの取引開始による入力規則とワークフロートリガの実行]が選択されておりリード取引開始によって作成された商談にApexトリガが関連付けられている場合そのトリガは商談が作成された直後かつ商談の取引先責任者ロールが作成される前に実行されます詳細はSalesforcecom オンラインヘルプの「リード設定のカスタマイズ」を参照してください
bull beforeトリガを設定し商談レコードの [フェーズ]および [売上予測分類]を設定する場合次のように動作します
- [フェーズ]および [売上予測分類]を設定すると商談レコードにはこれらの正確な値が含まれます- [フェーズ]を設定して [売上予測分類]を設定しない場合商談レコードの [売上予測分類]のデフォルト値
はトリガ [フェーズ]に関連した値になります- [フェーズ]を API で指定した値またはユーザーインターフェースから受信した値にリセットすると[売
上予測分類]値も API コールまたはユーザーインターフェースに由来するものでなければなりません[売上予測分類]の値を指定せず入力される [フェーズ]がトリガ [フェーズ]とは異なる場合[売上予測分類]のデフォルト値は [フェーズ]に関連する値となりますトリガ [フェーズ]および入力する [フェーズ]
が同じ場合[売上予測分類]のデフォルト値は設定されません
bull 商品を含む商談をコピーする場合次のイベントが順に発生します
1 親商談は上記のイベントリストに従って保存されます2 商談商品は上記のイベントリストに従って保存されます
メモ商談商品でエラーが発生する場合は商談に戻ってエラーを解決してからコピーを行う必要があります
商談商品に固有のカスタム項目が含まれている場合それらをすべて Null にしてから商談をコピーする必要があります
トリガを開始しない操作トリガはJava アプリケーションサーバによって開始されたまたは処理されるデータ操作言語 (DML) 操作に対してのみ呼び出されますそのためシステムによるいくつかの一括処理ではトリガを呼び出しません例には次のものが含まれます
bull 削除操作のカスケードdeleteを開始していないレコードではトリガの評価を行いませんbull 結合操作の結果として再び親となる子レコードの更新のカスケードbull キャンペーンステータスの一括変更bull ディビジョンの一括転送bull 住所の一括更新bull 承認要求の一括転送bull 電子メールの一括送信
Apex の呼び出し Version 180 | トリガを開始しない操作 | 75
bull カスタム項目のデータ型の変更bull 選択リストの名前変更または置換bull 価格表の管理bull 転送ディビジョンオプションがオンになっているユーザのデフォルトディビジョンの変更
メモ 個人取引先の挿入更新削除を行うと取引先担当者トリガではなく取引先トリガが発生します
リードの取引開始処理の場合リードの取引開始時の入力規制およびトリガが有効化されている場合のみ次の操作に関連する beforeトリガが発生します
bull 取引先連絡先商談の insert
bull 取引先および連絡先の update
商談の商談製品を変更する場合または商談製品のスケジュールで商談製品が変更される場合商談製品によって商談が変更される場合でも商談の before トリガおよび after トリガ検証ルールは発生しませんただしロールアップ要約項目が更新され商談に関連するワークフロールールが実行されます
PageReference オブジェクトの getContentメソッドはトリガ内で使用できません
ContentVersion オブジェクトについては次の点に注意してください
bull スライドおよびスライドの自動修正などContentVersion オブジェクトを使用するコンテンツパック操作はトリガを開始しません
メモ パック内のスライドが修正されるとコンテンツパックが修正されます
bull TagCsvContentSizeおよびVersionData項目の値はContentVersion レコードを作成または更新する要求が API から作成される場合にのみ使用できます
bull ContentVersion オブジェクトの delete トリガの前後で使用することはできません
トリガで更新できない項目一部の項目値はbeforeトリガが発生した後に行われるシステムの save 操作時に設定されます結果としてこれらの項目は変更できずまた before insertトリガまたは before updateトリガで正確に検出できません例には次のものが含まれます
bull TaskisClosed
bull Opportunityamountbull OpportunityForecastCategory
bull OpportunityisWon
bull OpportunityisClosed
bull ContractactivatedDate
bull ContractactivatedById
bull CaseisClosed
bull SolutionisReviewed
bull Id (すべてのレコード)bull createdDate (すべてのレコード)bull lastUpdated (すべてのレコード)
Apex の呼び出し Version 180 | トリガで更新できない項目 | 76
Opportunityに lineitemsがない場合Amountは beforeトリガによって変更することはできません
Idおよび createdDateは before updateトリガで検出できますが変更はできません
トリガの例外トリガを使用してレコードまたは項目に addError()メソッドを呼び出してDML 操作が行われないようにすることができますinsertトリガおよび updateトリガの Triggernewレコードまたは deleteトリガのTriggeroldレコードに使用するとアプリケーションインターフェースおよびログにカスタムエラーメッセージが表示されます
メモ エラーを beforeトリガで追加すると応答時間の遅延がほとんど生じません
処理されるレコードのサブセットはaddError()メソッドでマークできます
bull トリガが Apex の DML ステートメントにより実行される場合 つのエラーはすべての処理に対するロールバックを引き起こしますただしランタイムエンジンはすべてのレコードを処理して完全なエラーリストを生成します
bull トリガが Forcecom API の DML 一括処理により実行される場合ランタイムエンジンは不正なレコードを除外しエラーのないレコードのみを保存します「DML 例外の一括処理」 (ページ205)を参照してください
トリガが未処理の例外を投げた場合すべてのレコードがエラーとしてマークされそれより先の処理は行われません
Apex スケジューラ
Apex クラスを呼び出し特定の時間に実行するにはまずクラスに Schedulableを実装し page in theSalesforcecom ユーザインターフェースの [Apex をスケジュール] ページまたは Systemscheduleメソッドを使用してスケジュールを指定します
[Apex をスケジュール] の詳細はSalesforcecom オンラインヘルプの「Apex のスケジュール」を参照してください
重要 Salesforcecom ではスケジュールされた時間のキューの処理だけを追加します実際の実行はサービスの使用可能状態に応じて遅れる場合があります
一度に使用できるスケジュールクラスは 10 件ですSalesforcecom の [スケジュール済みジョブ] を表示してまたはプログラムで Forcecom Web サービス API を使用して AsyncApexJob オブジェクトを問い合わせて現在のカウントを評価できます
クラスをトリガからスケジュールする場合は細心の注意を払ってくださいトリガは 10 件を超えるスケジュールクラスを追加しないようにする必要があります具体的にはAPI の一括更新インポートウィザードユーザインターフェースを使用した一括レコードの変更および複数のレコードを一度に更新できるすべてのケースなどです
Schedulableインターフェースの実装
一定の間隔で実行されるようにApexクラスのスケジュールを設定するにはまず Salesforcecomが提供するインターフェース Schedulableを実装する Apex クラスを記述します
Apex の呼び出し Version 180 | トリガの例外 | 77
スケジューラはシステムとして稼動しますユーザがクラスを実行する権限を持っているかどうかに関係なくすべてのクラスが実行されますクラス権限設定の詳細はSalesforcecom オンラインヘルプの「Apex クラスセキュリティの設定」を参照してください
Salesforcecom ユーザインターフェースを使用してスケジュールされた Apex ジョブの実行を監視または停止するには[設定] [監視] [スケジュール済みジョブ] をクリックします詳細はSalesforcecom オンラインヘルプの「スケジュール済みジョブの監視」を参照してください
Systemscheduleメソッドを使用してスケジュール済みジョブの実行を停止するにはSystemabortJobメソッドを使用します
Schedulableインターフェースには実装が必要な 1 つのメソッド executeが含まれています
global void execute(SchedulableContext sc)
スケジュール済みジョブを記録するにはSchedulableContext オブジェクトを使用しますSchedulableContext メソッド getTriggerIdはこのスケジュール済みジョブに関連付けられている CronTrigger オブジェクトの IDを文字列として返しますこのメソッドはスケジュール済みジョブの進行状況を追跡するために使用します
このメソッドはスケジュールを設定するクラスのインスタンスを作成するために使用します
ヒント executeメソッドで追加処理を行うことはできますがSalesforcecomではすべての処理が別個のクラスで行われるようにすることをお勧めします
次の例ではmergeNumbersと呼ばれるクラスの Schedulableインターフェースを実装します
global class scheduledMerge implements Schedulable global void execute(SchedulableContextSC) mergeNumbers M = new mergeNumbers()
次の例では前述のクラスを実装するための SystemScheduleメソッドを使用します
scheduledMerge m = new scheduledMerge() String sch = 20 30 8 10 2 systemschedule(MergeJob sch m)
Apex の一括処理クラスで Schedulableインターフェースを使用することもできます次の例ではbatchable
と呼ばれる Apex の一括処理クラスの Schedulableインターフェースを実装します
global class scheduledBatchable implements Schedulable global void execute(SchedulableContextsc) batchable b = new batchable() databaseexecutebatch(b)
Apex スケジューラのテスト
次はApex スケジューラを使用してテストする方法についての例を示します
これがテストするクラスです
global class TestScheduledApexFromTestMethod implements Schedulable Run the scheduledjob at midnight Sept 3rd2022 public static String CRON_EXP = 0 0 0 3 9 2022 globalvoid execute(SchedulableContext ctx) CronTrigger ct = [SELECT id CronExpressionTimesTriggered NextFireTime FROM CronTrigger WHERE id = ctxgetTriggerId()]SystemassertEquals(CRON_EXP ctCronExpression) SystemassertEquals(0 ctTimesTriggered)SystemassertEquals(2022-09-03 000000 StringvalueOf(ctNextFireTime)) Account a =[SELECT id name FROM Account WHERE name = testScheduledApexFromTestMethod] aname =testScheduledApexFromTestMethodUpdated update a
Apex の呼び出し Version 180 | Apex スケジューラ | 78
次で上記のクラスをテストします
istest class TestClass static testmethod void test() TeststartTest() Account a = newAccount() aname = testScheduledApexFromTestMethod insert a Schedule the test jobString jobId = Systemschedule(testBasicScheduledApexTestScheduledApexFromTestMethodCRON_EXP new TestScheduledApexFromTestMethod()) Getthe information from the CronTrigger API object CronTrigger ct = [SELECT id CronExpressionTimesTriggered NextFireTime FROM CronTrigger WHERE id = jobId] Verify the expressionsare the same SystemassertEquals(TestScheduledApexFromTestMethodCRON_EXPctCronExpression) Verify the job has not run SystemassertEquals(0 ctTimesTriggered) Verify the next time the job will run SystemassertEquals(2022-09-03 000000StringvalueOf(ctNextFireTime))SystemassertNotEquals(testScheduledApexFromTestMethodUpdated [SELECT id name FROMaccount WHERE id = aid]name) TeststopTest()SystemassertEquals(testScheduledApexFromTestMethodUpdated [SELECT id name FROM accountWHERE id = aid]name)
SystemScheduleメソッドの使用
Schedulableインターフェースでクラスを実装したらSystemScheduleメソッドを使用して実行しますスケジューラはシステムとして稼動しますユーザがクラスを実行する権限を持っているかどうかに関係なくすべてのクラスが実行されます
メモ クラスをトリガからスケジュールする場合は細心の注意を払ってくださいトリガは 10 件を超えるスケジュールクラスを追加しないようにする必要があります具体的にはAPI の一括更新インポートウィザードユーザインターフェースを使用した一括レコードの変更および複数のレコードを一度に更新できるすべてのケースなどです
SystemScheduleメソッドはジョブの名前ジョブの実行予定日時を表すために使用する式クラスの名前という 3 つの引数を取りますこの式の構文は次のとおりです
Seconds Minutes Hours Day_of_month Month Day_of_week optional_year
メモ Salesforcecom ではスケジュールされた時間のキューの処理だけを追加します実際の実行はサービスの使用可能状態に応じて遅れる場合があります
SystemScheduleメソッドではすべてのスケジュールの基準としてユーザのタイムゾーンが使用されます
式の値は次のようになります
特殊文字値名前None0ndash59Seconds
None0ndash59Minutes
- 0ndash23Hours
- L W1ndash31Day_of_month
- 1-12または次のとおりMonth
bull JAN
bull FEB
bull MAR
bull APR
Apex の呼び出し Version 180 | Apex スケジューラ | 79
特殊文字値名前
bull MAY
bull JUN
bull JUL
bull AUG
bull SEP
bull OCT
bull NOV
bull DEC
- L 1-7または次のとおりDay_of_week
bull SUN
bull MON
bull TUE
bull WED
bull THU
bull FRI
bull SAT
- Null または 1970-2099optional_year
特殊文字の定義は次のとおりです
bull は値を区切りますたとえば複数の月を指定する場合は JAN MAR APRを使用しますbull - は範囲を指定しますたとえば複数の月を指定する場合は JAN-MARを使用しますbull はすべての値を指定しますたとえばMonthをと指定するとジョブは毎月にスケジュールされますbull は特定の値を指定しませんこれはDay_of_monthと Day_of_weekのみで使用でき一般にある値以
外を指定しない場合に使用しますbull は増分を指定しますスラッシュの前の数値は期間の開始を指定しスラッシュの後の数値は期間の長さ
を指定しますたとえばDay_of_monthに 15と指定した場合Apex クラスは月の 1 日から始まり5 日おきに実行されます
bull L は範囲の終了を指定しますこれはDay_of_monthと Day_of_weekでのみ使用できますDay of month
で使用するとLは 1 月 31 日うるう年の場合は 2 月 28 日など常に月末日を意味しますDay_of_week
のみで使用すると7または SATを意味しますDay_of_weekの値と一緒に使用するとその月で指定した曜日の最後を意味しますたとえば2Lと指定すると月の最終月曜日を指定することになりますLと一緒に値の範囲は使用しないでください予期しない結果が生じる場合があります
bull W は特定の日に最も近い平日 (月曜日 金曜日) を指定しますこれは Day_of_monthでのみ使用できますたとえば20Wと指定し20 日が土曜日の場合クラスは 19 日に実行されます1Wと指定すると1 日が土曜日の場合クラスはその前の月ではなく次の月曜日である 3 日に実行されます
ヒント 月の最後の平日を指定するにはLと Wを一緒に使用します
bull は weekdayday_of_monthという形式で月の第 nth日目を指定しますこれは Day_of_weekでのみ使用できますの前の数値で平日 (SUN-SAT) を指定しますの後ろの数値で月の日付を指定しますたとえば22と指定するとクラスは毎月第 2 月曜日に実行されることを意味します
Apex の呼び出し Version 180 | Apex スケジューラ | 80
式の使用法の例を次に示します
説明式
クラスは毎日午後 1 時に実行されます0 0 13
クラスは毎月最終金曜日の午後 10 時に実行されます0 0 22 6L
クラスは月曜日から金曜日の午前 10 時に実行されます
0 0 10 MON-FRI
クラスは 2010 年の毎日午後 8 時に実行されます0 0 20 2010
次の例ではクラス proscheduleによって Schedulableインターフェースが実装されますこのクラスは2月 13 日の午前 8 時に実行するようにスケジュールされています
proschedule p = new proschedule() String sch = 0 0 8 13 2 systemschedule(One TimePro sch p)
Apex スケジューラのベストプラクティス
bull Salesforcecom ではスケジュールされた時間のキューの処理だけを追加します実際の実行はサービスの使用可能状態に応じて遅れる場合があります
bull クラスをトリガからスケジュールする場合は細心の注意を払ってくださいトリガは 10 件を超えるスケジュールクラスを追加しないようにする必要があります具体的にはAPIの一括更新インポートウィザードユーザインターフェースを使用した一括レコードの変更および複数のレコードを一度に更新できるすべてのケースなどです
bull executeメソッドで追加処理を行うことはできますがSalesforcecom ではすべての処理が別個のクラスで行われるようにすることをお勧めします
bull 一度に使用できるスケジュールクラスは 10 件ですSalesforcecomの [スケジュール済みジョブ] を表示してまたはプログラムで Forcecom Web サービス API を使用して AsyncApexJob オブジェクトを問い合わせて現在のカウントを評価できます
匿名ブロック
匿名ブロックとはメタデータには格納されないものの次のいずれかをを使用して次のように実行されるApexスクリプトです
bull システムログコンソールbull Forcecom IDEbull executeAnonymous Forcecom Web サービス API コールは次のようになります
ExecuteAnonymousResult executeAnonymous(String code)
System Log コンソールまたは Forcecom IDE やランタイム時に動的に変化するスクリプトの記述などでApexを素早く評価するために匿名ブロックを使用できますたとえばユーザが名前や住所などの値を入力するクラ
Apex の呼び出し Version 180 | 匿名ブロック | 81
イアント側の Web アプリケーションを記述するとしますその場合Apex の匿名ブロックを使用しその名前と住所の連絡先をデータベースに書き込むことができます
匿名ブロックの内容については次の点に注意してください (executeAnonymouscode文字列)
bull ユーザ定義メソッドおよび例外を含めることができますbull ユーザ定義メソッドに staticキーワードを含めることはできませんbull データベースへの変更は手動でコミットする必要はありませんbull Apexスクリプトが正常に完了するとデータベースへのすべての変更は自動的にコミットされますApexス
クリプトが正常に完了しない場合データベースへのすべての変更はロールバックされますbull クラスやトリガとは異なり匿名ブロックは現在のユーザとして実行されスクリプトがユーザオブジェク
トの権限および項目レベルの権限に違反する場合コンパイルが失敗しますbull ローカル以外のスコープを含まないでくださいたとえばglobalアクセス修飾子を使用できますが意味
はありませんメソッドのスコープは匿名ブロックに制限されています
ユーザ定義メソッドでは自身や後から使用されるメソッドを事前に宣言する必要はありませんが変数は宣言されるまで参照できないことにご注意ください次の例では整数 intを宣言する必要がありますがmyProcedure1は宣言する必要はありません
Integer int1 = 0
void myProcedure1() myProcedure2()
void myProcedure2() int1++
myProcedure1()
匿名ブロックで返される結果には次の情報が含まれます
bull 発生したすべてのエラーを含めたコールのコンパイルと実行フェーズのステータス情報bull Systemdebugメソッドへのすべてのコールの出力結果も含めたデバッグログの内容 (「デバッグログの理
解」を参照)bull 各コールのスタック要素に対するクラスメソッド行番号を含めた取得できなかったすべてのスクリプ
ト実行例外の Apex スタックトレース
executeAnonymous()の詳細は「Web サービス API コールおよび Apex の SOAP ヘッダ」 (ページ 406)を参照してください「System Log コンソールの使用」および「Forcecom IDE」も参照してください
AJAX での Apex
AJAX ツールキットには匿名ブロックや公開 webServiceメソッドを通じて Apex を起動するためのサポートが組み込まれてますそれにはAJAX コードに次の行を追加します
ltscript src=soapajax150connectionjs type=textjavascriptgtltscriptgt ltscriptsrc=soapajax150apexjs type=textjavascriptgtltscriptgt
メモ AJAX ボタンの場合これらを別の形式で使用します
Apex を起動するには次の 2 つのメソッドのいずれかを使用します
Apex の呼び出し Version 180 | AJAX での Apex | 82
bull sforceapexexecuteAnonymous (script)を通じて匿名で実行しますこのメソッドが返す結果は APIの結果型と似ていますがJavaScript 構造となります
bull WSDL クラスを使用しますたとえば次の Apex クラスをコールします
global class myClass webService static Id makeContact(String lastName Account a) Contact c = new Contact(LastName = lastName AccountId = aId) return cid
次の JavaScript コードを使用します
var account = sforcesObject(Account) var id =sforceapexexecute(myClassmakeContact lastNameSmith aaccount)
executeメソッドはプリミティブデータ型 Objects およびプリミティブデータ型または sObjects のリストを使用します
パラメータを使用せずに webService メソッドをコールするにはを sforceapexexecuteの 3 つ目のパラメータとして使用しますたとえば次の Apex クラスをコールするとします
global class myClass webService static String getContextUserName() returnUserInfogetFirstName()
次の JavaScript コードを使用します
var contextUser = sforceapexexecute(myClass getContextUserName )
メモ 組織内で名前空間が定義されている場合クラスを起動するときにその名前を JavaScript コードに含める必要がありますたとえば上記のクラスをコールするにはJavaScript を次のように書き換えます
var contextUser = sforceapexexecute(myNamespacemyClass getContextUserName)
組織内で名前空間が定義されているかどうかを確認するにはSalesforcecomの組織にログインし[設定] [作成] [パッケージ] にアクセスします名前空間が定義されている場合[開発者設定] の中に表示されます
どちらの例の結果もメソッドの戻り値の型を表すネイティブな JavaScript 値となります
次の行を使用してデバッグ情報を含むポップアップ ウィンドウを表示します
sforcedebugtrace=true
Apex の呼び出し Version 180 | AJAX での Apex | 83
第 4 章
クラスオブジェクトおよびインターフェース
クラスはApex オブジェクト作成するためのテンプレートつまり設計図で他のクラスユーザ定義メソッド変数例外タイプおよび
トピック
bull クラスを理解する static 初期設定化コードで構成されますクラスオブジェクトおよびbull インターフェースおよび拡張クラ
スインターフェースはアプリケーションの [設定] [開発] [Apexクラス] に格納されています
bull キーワード 正常に保存されるとクラスメソッドや変数は他の Apex スクリプトからまたはwebServiceキーワードで指定されたメソッドのForcecombull アノテーション
bull クラスとキャスト Web サービス API (または AJAX ツールキット) を介して呼び出すことができますbull Apex クラスと Java クラスの違いほとんどの場合ここで紹介するクラスの概念は Java のカウンターパートでモデリングされておりJava での経験があればすぐに理解することができます
bull クラス定義作成bull クラスセキュリティbull 名前空間プレフィックスbull バージョン設定 bull クラスについて Apex のクラス作成の詳細
bull インターフェースおよび拡張クラスインターフェースに関する情報bull キーワードおよびアノテーションクラスメソッドまたは変数の
追加の修飾子bull クラスとキャストあるデータ型のクラスの別のデータ型への割り当
てbull Apex クラスと Java クラスの違い Apex と Java の違いbull クラス定義作成およびクラスのセキュリティユーザーがクラスにア
クセスできるようにするほかSalesforcecomユーザーインターフェースでのクラスの作成
bull 名前空間プレフィックスおよびバージョン設定名前空間プレフィックスの使用および Apex クラスのバージョニング
クラスを理解する
Java と同じようにApexではクラスを作成可能ですクラスはオブジェクトを作成するためのテンプレートつまり設計図ですオブジェクトはクラスのインスタンスです例えばPurchaseOrderクラスは注文全体と注文に伴う可能なすべてのことを示しますPurchaseOrderクラスのインスタンスが送受信する特定の注文書にあたります
すべてのオブジェクトには状態と振る舞いつまりオブジェクト自体に関する情報とオブジェクトが実行できる処理がありますPurchaseOrder オブジェクトの状態つまりオブジェクト自体の情報には送信元のユーザ作成日時重要性を表すフラグの有無などがありますPurchaseOrder の動作つまり実行できる処理には在庫の確認製品の出荷または顧客への通知が含まれます
クラスには変数とメソッドが含まれます変数はオブジェクトの Nameや Typeなどオブジェクトの状態を指定するために使用されますこれらの変数はクラスに関連付けられておりクラスのメンバーであるため一般にメンバー変数と呼ばれますメソッドはgetOtherQuotesや copyLineItemsなど動作を制御するために使用されます
インタフェースはメソッドが実装されていないクラスのようなものですメソッドのシグネチャはありますが各メソッドの本文は空です インターフェースを使用するにはインターフェースに含まれるすべてのメソッドの本文を提供することによって別のクラスがインターフェースを実装する必要があります
クラスオブジェクトおよびインタフェースに関する詳細についてはhttpjavasuncomdocsbookstutorialjavaconceptsindexhtml を参照してください
Apex クラスの定義Apex ではトップレベルのクラス (外部クラスとも呼ぶ) とクラス内に定義されているクラスである内部クラスの両方を定義できます内部クラスは1 つ下のレベルのみです例
public class myOuterClass 追加の myOuterClass コードをここに記述class myInnerClass myInnerClass コードをここに記述
クラスを定義するには以下を指定します
1 アクセス修飾子
bull トップレベルのクラスの宣言にはpublicまたはglobalなどのアクセス修飾子の 1 つを使用しなければなりません
bull 内部クラスの宣言にはアクセス修飾子を使用する必要はありません
2 オプションの定義修飾子 (virtualや abstractなど)3 必須 クラス名に続くキーワード class
4 オプションの拡張および実装またはそのいずれか
クラスを定義するには次の構文を使用します
private | public | global [virtual | abstract | with sharing | without sharing | (none)]class ClassName [implements InterfaceNameList | (none)] [extends ClassName | (none)] クラスのボディ
クラスオブジェクトおよびインターフェース Version 180 | クラスを理解する | 85
bull privateアクセス修飾子はこのクラスがローカルからのみ見えるつまりコードのこのセクションからのみ見えることを宣言しますこれが内部クラスのデフォルトアクセスですつまり内部クラスにアクセス修飾子を指定しない場合privateとみなされますこのキーワードは内部クラスでのみ使用できます
bull publicアクセス修飾子はこのクラスがアプリケーションや名前空間から見えることを宣言しますbull globalアクセス修飾子はこのクラスがすべてのApexスクリプトから見えることを宣言しますwebService
キーワードと共に定義されているメソッドを含むすべてのクラスはglobalとして宣言する必要がありますメソッドまたは内部クラスを globalとして宣言した場合外部のトップレベルクラスも globalとして宣言する必要があります
bull with sharingおよび without sharingの各キーワードはこのクラスの共有モードを指定します詳細はwith sharingまたはwithout sharingキーワードを使う (ページ 105)を参照してください
bull virtual定義修飾子はこのクラスが拡張やオーバーライドを許可することを宣言しますクラスがvirtual
として定義されていなければoverrideキーワードを使用したメソッドをオーバーライドはできませんbull abstract定義修飾子はこのクラスには abstract メソッドを含むつまりシグネチャのみが宣言されてお
りボディが定義されていないメソッドが含まれていることを宣言します
メモ
bull Developer Edition 組織では virtualまたは abstractのいずれかで宣言されたクラスを globalとして宣言することはできませんSandbox 組織では globalとして定義できますDeveloper Edition 組織では privateおよび publicクラスのみを virtualまたは abstractのいずれかで定義できますただしDeveloper Edition 組織または Sandbox 組織でglobalとして定義したクラスは virtual またはabstract クラスを拡張できます
bull クラスが「管理-リリース済み」パッケージバージョンでアップロードされた後に抽象クラスまたは仮想クラスにメソッドを追加することはできません管理パッケージの詳細は「管理パッケージでの Apex の開発 (ページ 165)」を参照してください
クラスは複数のインターフェースを実装できますが既存のクラスを 1 つしか拡張できませんこの制限はApex が複数の継承をサポートしていないことを意味していますリストのインターフェース名はカンマで区切られていますインターフェースの詳細は「インターフェースおよび拡張クラス」 (ページ 97)を参照してください
メソッドと変数のアクセス修飾子の詳細は「アクセス修飾子」 (ページ 92)を参照してください
拡張クラス例以下にApex クラスのすべての機能と共に拡張クラスの例を示します例におけるキーワードを概念はこの章全体を通じてさらに詳細に説明します
トップレベル (外部) クラスは public または global に設定しなければなりません (Web サービスが含まれている場合は globalそれ以外は通常 public に設定します) public class OuterClass
静的ファイナル変数 (定数)外部レベルクラスのみprivate static final Integer MY_INT
非ファイナルな静的変数この変数は単一要求内でのトリガ間の通信に 使用しますpublic static StringsharedState
静的メソッド外部クラスレベルのみpublic static Integer getInt() return MY_INT
静的な初期化 (変数が定義されている箇所に含めることができます)static MY_INT = 2
外部クラスのメンバー変数private final String m
クラスオブジェクトおよびインターフェース Version 180 | 拡張クラス例 | 86
インスタンス初期化ブロック変数を宣言している箇所もしくは コンストラクタで実行できます m = a
コンストラクタはこの外部クラスでは明示的に定義されていないため 暗黙的で引数を取らない公開コンストラクタが存在します
内部インターフェースpublic virtual interface MyInterface
インターフェースメソッドではアクセス修飾子は不要です これらはインターフェースの可視性により常にpublic または global となりますvoid myMethod()
インターフェース拡張interface MySecondInterface extends MyInterface Integer method2(Integeri)
内部クラスvirtual であるため拡張可能です このクラスはインターフェースを拡張しそのインターフェースは代わりに別のインターフェースを拡張します そのためクラスはすべてのメソッドを実装する必要がありますpublic virtual class InnerClass implements MySecondInterface
内部メンバー変数private final String s private final String s2
内部インスタンス初期化ブロック (このコードは上記に記述することもできます) thiss = x
インライン初期化 (上記のブロックが実行された後に発生します)private final Integer i = slength()
明示的な引数を取らないコンストラクタInnerClass() 後で定義される別のコンストラクタを起動しますthis(none)
ファイナル変数値を割り当てるコンストラクタpublic InnerClass(String s2) thiss2 = s2
MyInterface からメソッドを実装するインスタンスメソッド virtual として宣言されているためサブクラスによってオーバーライドできますpublic virtual void myMethod() なにも実行しない
上記の 2 つめのインターフェースメソッドの実装 このメソッドはメンバー変数を参照します (「this」接頭辞がある場合もない場合もあります)public Integer method2(Integer i) return thisi + slength()
Abstract クラス (上記のクラスのサブクラス)親クラスが引数と取らないコンストラクタであるため コンストラクタは不要ですpublic abstract class AbstractChildClass extends InnerClass
このシグネチャで親クラスのメソッドをオーバーライド override キーワードを使用しなければなりませんpublic override void myMethod() 別の処理を実行
親クラスメソッドを同じ名前で異なるシグネチャ これは異なるメソッド (ポリモルフィズムの表示) であるため override キーワードを使用する必要はありませんprotected void method2()
Abstract メソッドこのクラスのサブクラスはこのメソッドを実装する必要がありますabstract IntegerabstractMethod()
abstract メソッドを実装しabstract クラスを完了public class ConcreteChildClass extendsAbstractChildClass 親メソッドの可視性を拡張します可視性は サブクラスでは制限されないことにご注意くださいpublic override Integer abstractMethod() return 5
元の InnerClass の 2 つ目のサブクラスpublic class AnotherChildClass extends InnerClass AnotherChildClass(String s) 引数を取らないコンストラクタの代わりに別のスーパーコンストラクタを明示的に起動しますsuper(s)
例外内部クラスpublic virtual class MyException extends Exception 例外クラスのメンバー変数public Double d
クラスオブジェクトおよびインターフェース Version 180 | 拡張クラス例 | 87
例外クラスのコンストラクタMyException(Double d) thisd = d
protected とマークされた例外クラスメソッドprotected void doIt()
例外クラスはabstract または implement インターフェースとすることができますpublic abstract classMySecondException extends Exception implements MyInterface
このコード例は次を示します
bull トップレベル定義 (外部クラスとも呼ぶ)bull トップレベルクラスの静的変数および静的メソッドおよび静的初期化コードブロックbull トップレベルクラスのメンバー変数とメソッドbull ユーザ定義のコンストラクタが存在しないクラス暗黙的で引数をとらないコンストラクタを含むbull トップレベルクラスのインターフェース定義bull 別のインターフェースを拡張するインターフェースbull トップレベルクラス内の内部クラス定義 (1 つ下のレベル)bull メソッドシグネチャの公開バージョンを実装することでインターフェース (つまり関連付けられているサブ
インターフェース) を実装するクラスbull 内部クラスコンストラクタ定義と呼び出しbull 内部クラスメンバー変数とthisキーワード (引数なし) を使用したその変数の参照bull 別のコンストラクタの起動に thisキーワード (引数なし) を使用する内部クラスコンストラクタbull コンストラクタ外 (変数が定義されている箇所と中かっこ () で囲まれた匿名のブロックの両方) の初期化
コードこれらのコードはJava と同様にファイルに記述されている順序どおりにすべてのコンストラクションと共に実行されることにご注意ください
bull クラス拡張と抽象クラスbull 基本のクラスメソッドをオーバーライドするメソッド (virtualとして宣言する必要がある)bull サブクラスメソッドをオーバーライドするメソッドの overrideキーワードbull 抽象メソッドとコンクリートサブクラスによる実装bull protectedアクセス修飾子bull ファーストクラスオブジェクトとしての例外とそのメンバーメソッドコンストラクタ
この例では上記のクラスを別の Apex スクリプトからコールする方法を示します
内部コンクリートクラスのインスタンスとユーザ定義コンストラクタと共にコンストラクトOuterClassInnerClass ic = new OuterClassInnerClass(x)
そのクラスのユーザ定義メソッドをコールSystemassertEquals(2 icmethod2(1))
インターフェースデータ型で変数を定義しその変数に そのインターフェースを実装する型を割り当てOuterClassMyInterface mi = ic
通常通りに instanceof および casting を使用OuterClassInnerClass ic2 = mi instanceofOuterClassInnerClass (OuterClassInnerClass)mi null Systemassert(ic2 = null)
外部タイプをコンストラクトOuterClass o = new OuterClass() SystemassertEquals(2OuterClassgetInt())
抽象クラスの子のインスタンスをコンストラクトSystemassertEquals(5 newOuterClassConcreteChildClass()abstractMethod())
無効です抽象クラスをコンストラクトできません new OuterClassAbstractChildClass()
クラスオブジェクトおよびインターフェース Version 180 | 拡張クラス例 | 88
無効ですインスタンスから静的メソッドにアクセスできません ogetInt()
無効です外部から protected メソッドをコールできません newOuterClassConcreteChildClass()method2()
このコード例は次を示します
bull 外部クラスのコンストラクトbull 内部クラスのコンストラクトと内部インターフェース型の宣言bull インターフェース型として宣言された変数をインターフェースを実装するクラスのインスタンスに割り当
てbull そのインターフェースを実装するクラスタイプにインターフェース変数をキャスト (instanceof演算子を使
用した検証後)
クラス変数の宣言変数を宣言するには以下を指定します
bull オプション publicfinalstaticなどの修飾子bull 必須 StringBoolean などの変数のデータ型bull 必須 変数の名前bull オプション 変数の値
変数を定義するには次の構文を使用します
[public | private | protected | global | final] [static] data type variable name [= value]
例
private static final Integer MY_INT private final Integer i = 1
クラスメソッドの定義メソッドを定義するには以下を指定します
bull オプション publicや protectedなどの修飾子bull 必須 String や Integer などメソッドが返す値のデータ型メソッドが値を返さない場合はvoidを使用し
ますbull 必須カンマで区切られかっこ()で囲まれたメソッドの入力パラメータのリスト後にデータ型が続きます
パラメータがない場合は1 組の空のかっこを使用しますメソッドに指定できるパラメータは 32 個までです
bull 必須 中かっこ で囲まれたメソッドのボディローカル変数宣言を含めたメソッドのすべてのコードがここに含まれます
メソッドを定義するには次の構文を使用します
(public | private | protected | global ) [override] [static] data type method name (inputparameters) メソッドのボディ
クラスオブジェクトおよびインターフェース Version 180 | クラス変数の宣言 | 89
メモ virtualとして定義されたクラスのメソッドをオーバーライドするにはoverrideを使用します
例
public static Integer getInt() return MY_INT
Java の場合と同様に結果が別の変数に割り当てられない場合値を返すメソッドもステートメントとして実行できます
ユーザー定義メソッドの次の点に注意してください
bull システムメソッドが使用されている場合はいつでも使用できますbull メソッドに渡され変更された変数がメソッドをコールした元のコードでも変更されるよう参照によって
引数を渡しますbull 再帰する場合がありますbull sObject ID を初期化する DML insertステートメントなど悪影響の可能性があります「Apex のデータ操
作言語 (DML) 操作 (ページ 186)」を参照してくださいbull ユーザー定義メソッド自体または同じクラスまたは匿名ブロックで後で定義されたメソッドを参照できます
Apex は2 つのフェーズでメソッドを解析しますそのため事前の宣言は必要ありませんbull 多型の場合がありますたとえばfooというメソッドは 2 とおりに実行できます一方は単一の Integer パ
ラメータでもう一方は 2 つの Integer パラメータで実行できますメソッドを 1 つの Integers でコールするかまたは 2 つの Interger でコールするかによってApex パーサーは適切な実行を選択しますパーサーが完全一致を検出できない場合データ型強制規則を使用しておおよその一致を検索しますデータ変換のは「変換の規則について」 (ページ 39)を参照してください
メモ パーサーがおおよその一致を複数検出した場合解析時間の例外が生成されます
bull トリガで使用する場合staticとして宣言することはできませんbull 副次的影響のある void メソッドを使用する場合ユーザ定義メソッドがApexスクリプトでスタンドアロンの
プロシージャステートメントとして実行されます例
Systemdebug(ログ用のメモです)
bull 結果が別の変数に割り当てられない場合戻り値をステートメントとして実行するステートメントを指定できますこれは Java と同じです
コンストラクタの使用コンストラクタとはクラスの設計図からオブジェクトを作成したときに起動されるコードですすべてのクラスでコンストラクタを記述する必要はありませんクラスにユーザ定義のコンストラクタが存在しない場合暗黙的で引数をとらない公開コンストラクタが使用されます
コンストラクタの構文はメソッドと似ていますがコンストラクタには明示的な戻り値のタイプがないことと作成元のオブジェクトから継承されないという点がメソッドとは異なります
クラスオブジェクトおよびインターフェース Version 180 | コンストラクタの使用 | 90
クラスのコンストラクタを記述した後にコンストラクタを使用しそのクラスのオブジェクトをインスタンス化するには必ず newキーワードを使用しなければなりませんたとえば次のクラスを使用するとします
public class TestObject
引数のないコンストラクタpublic TestObject() ここにさらにコードを記述
このタイプの新しいオブジェクトは次のコードを使用してインスタンス化できます
TestObject myTest = new TestObject()
引数を取るコンストラクタを記述した場合記述したコンストラクタを使用してその引数を使用するオブジェクトを作成できます引数を取るコンストラクタを作成したものの引数を取らないコンストラクタを使用したい場合そのようなコンストラクタをコードに含める必要がありますクラスのコンストラクタを作成後はデフォルトの引数を取らない公開コンストラクタにアクセスする必要はありません自分で作成しなければなりません
Apex ではコンストラクタは オーバーロードつまりクラスにそれぞれ異なるパラメータを持つコンストラクタを 1 つ以上持つことができます次の例では引数のないものと単純な整数の引数を取るものの 2 つのコンストラクタを持つクラスを示していますまたthis()構文を使用して 1 つのコンストラクタから別のコンストラクタをコールする方法についても説明していますこの手法はコンストラクタチェーニングとも呼ばれます
public class TestObject2
private static final Integer DEFAULT_SIZE = 10
Integer size
引数のないコンストラクタpublic TestObject2() this(DEFAULT_SIZE) this() を使用し引数を 1 つ取るコンストラクタをコール
引数を 1 つ取るコンストラクタpublic TestObject2(Integer ObjectSize) size = ObjectSize
このタイプの新しいオブジェクトは次のコードを使用してインスタンス化できます
TestObject2 myObject1 = new TestObject2(42) TestObject2 myObject2 = new TestObject2()
クラスのために作成した各コンストラクタはそれぞれ異なる引数リストを持つ必要があります次の例のすべてのコンストラクタを持つことは可能です
public class Leads
最初は引数のないコンストラクタpublic Leads ()
引数を 1 つ取るコンストラクタpublic Leads (Boolean call)
引数を 2 つ取るコンストラクタpublic Leads (String email Boolean call)
このコンストラクタは上記のコンストラクタと同じ引数を取るものの 順序が異なっているため有効ですpublicLeads (Boolean call String email)
クラスオブジェクトおよびインターフェース Version 180 | コンストラクタの使用 | 91
新しいクラスを定義する場合新しいデータ型を定義することになりますそのクラス名はStringBooleanAccount など他のデータ型の名前を使用する場所であればどこででも使用できます型がクラスである変数を定義する場合それに割り当てるオブジェクトはそのクラスまたはサブクラスのインスタンスでなければなりません
アクセス修飾子Apex ではメソッドや変数の定義で privateprotectedpublicglobalの各アクセス修飾子を使用できます
トリガや匿名ブロックでもアクセス修飾子を使用できますがApex の狭い範囲では使いやすくありませんたとえば匿名ブロックで globalとしてのメソッドを宣言してもそのコードの外からコールすることはできません
クラスアクセス修飾子の詳細は「Apex クラスの定義」 (ページ 85)を参照してください
メモ インターフェースメソッドにはアクセス修飾子はありませんつねに global となります詳細は「インターフェースおよび拡張クラス」 (ページ 97)を参照してください
デフォルトではメソッドや変数は定義されたクラス内でのみ Apex に表示されますJava ではデフォルトでメソッドや変数は公開されるためこの点は Java とは異なりますApex は Java に比べると制限が大きく同じアプリケーション名前空間のクラスでメソッドや変数を利用するには明示的に公開であることを宣言する必要があります (「名前空間プレフィックス (ページ116)」を参照)次のアクセス修飾子を使用して表示のレベルを変更できますprivate
これはデフォルトですつまりメソッドや変数は定義された Apex クラス内でのみアクセスできますアクセス修飾子を指定しない場合メソッドや変数は privateとなります
protected
メソッドや変数は定義された Apex クラスのすべての内部クラスから参照できますこのアクセス修飾子はインスタンスメソッドやメンバー変数でのみ利用できますJava と同様にデフォルト (private) よりもより厳密な権限付与が必要であることにご注意ください
public
メソッドや変数はこのアプリケーションや名前空間のすべての Apex クラスで使用できます
メモ Apexではpublicアクセス修飾子は Java のものと同じではありませんアプリケーションの結合を妨げ各アプリケーションのコードを分離するための措置ですApex ではJava で行うように公開したい場合globalアクセス修飾子を使用します
global
ではメソッドや変数は同じアプリケーションの Apex スクリプトだけでなくクラスへのアクセス権のあるすべての Apex スクリプトで使用できますこのアクセス修飾子はForcecom Web サービス API やその他の Apex スクリプトのいずれかでアプリケーション外から参照する必要があるメソッドで使用しますメソッドまたは変数を globalとして宣言した場合それを含むクラスも globalとして宣言する必要があります
メモ Salesforcecom ではglobalアクセス修飾子は極力使用しないか全く使用しないことをお勧めしていますアプリケーション間の依存関係は維持が困難であるためです
クラスオブジェクトおよびインターフェース Version 180 | アクセス修飾子 | 92
privateprotectedpublicglobalアクセス修飾子を使用するには次の構文に従います
[(none)|private|protected|public|global] declaration
例
private string s1 = 1
public string gets1() return thiss1
静的およびインスタンスApexでは静的メソッド変数および初期化コードインスタンスメソッドメンバー変数および 変更子を含まない 初期化コードおよびローカル変数を持つことができます
bull 静的メソッド変数または初期化コードはクラスに関連していて外部クラス内でのみ可能ですstatic
としてメソッドまたは変数を宣言した場合クラスが読み込まれた時の一度だけ初期化されますbull インスタンスメソッドメンバー変数初期化コードは特定のオブジェクトと関連していて定義変更子
を持っていませんインスタンスメソッドメンバー変数初期化コードを宣言する場合そのクラスからインスタンス化された各オブジェクトと一緒にそのアイテムのインスタンスは作成されます
bull ローカル変数は宣言されたコードのブロックと関連付けられますすべての変数は使用前に初期化されなければなりません
以下はその範囲がifコードブロックの持続時間であるローカル変数の例です
Boolean myCondition = true if (myCondition) integer localVariable = 10
静的メソッドと変数を使う
静的メソッドと外部クラスを伴った変数のみが使用可能です内部クラスはメソッドや変数を持っていません静的メソッドや変数は実行するためにクラスのインスタンスを必要としません
あるクラスのすべての静的メンバー変数はそのクラスのオブジェクトの作成前に初期化されますこれには静的初期化コードブロックが含まれますこれらすべてはクラス内に現れる順に実行されます
静的メソッドは一般的にユーティリティー方式として使われ特定のインスタンスメンバー変数値に依存しません静的メソッドはクラスのみに関連するのでそのクラスのインスタンスメンバー変数値にはアクセスできません
静的変数は要求の範囲内で静的なだけですサーバー全体または全体組織においては静的ではありません
クラスの範囲内で共有される情報を保存するには静的変数を使ってください同じクラスのすべてのインスタンスは静的変数のシングルコピーです例えば同じ要求によって産まれるすべてのトリガは関連したクラス内の静的変数を見てアップデートすることによって互いと通信することができます再帰的なトリガはいつ再帰を終了するかを決定するためにクラス変数の値を使うかもしれません
以下のクラスを持っているとしましょう
public class p public static boolean firstRun = true
クラスオブジェクトおよびインターフェース Version 180 | 静的およびインスタンス | 93
このクラスを使うトリガは選択的にトリガーの最初の実行を失敗することができます
trigger t1 on Account (before delete after delete after undelete) if(TriggerisBefore)if(TriggerisDelete) if(pfirstRun) Triggerold[0]addError(Before Account DeleteError) pfirstRun=false
クラス静的変数はそのクラスの例を通してアクセスできません クラスCが静的変数Sを持っていてxがCのインスタンスの場合xSは不正表現です
以下のインスタンスメソッドに関しても同じですM()が静的メソッドの場合xM()は不正代わりにコードは以下のクラスを使った静的識別子を参照しますCSおよび CM()
ローカル変数がクラスネームと同じ名前の場合これらのメソッドと変数は隠されます
内部クラスは静的Java内部クラスのように機能しますがstaticキーワードを要求しません内部クラスは外部クラスのようにインスタンスメンバー変数を持つことができますが thisキーワードを使った 外部クラスのインスタンスへの暗黙的ポインタはありません
メモ 静的変数値はAPI バッチ間でリセットされますがガバナ制限はリセットされませんバッチを指定したバッチサイズより小さい塊に分割する場合があるためAPIバッチの状況に関する情報を追跡するために静的変数は使用しないでください
インスタンスメソッドと変数を使う
インスタンスメソッドとメンバー変数はクラスのインスタンスすなわちオブジェクトによって使われますインスタンスメンバー変数はメソッド内ではなくクラス内で宣言されますインスタンスメソッドはメソッド機能に影響するために通常インスタンスメンバー変数を使います
二次元のポイントを集めるクラスを持ちグラフ上にそれらをプロットしたいとします以下のスケルトンクラスがこれを示しますポイントのリストを保持するためのメンバー変数およびポイントの二次元リストを扱うための内部クラスを使います
public class Plotter
This inner class manages the points class Point Double x Double y
Point(Double x Double y) thisx = x thisy = y Double getXCoordinate() return x
Double getYCoordinate() return y
ListltPointgt points = new ListltPointgt()
public void plot(Double x Double y) pointsadd(new Point(x y))
The following method takes the list of points and does something with them public voidrender()
初期化コードを使う
初期化コードはクラス内で定義された以下のフォームのコードのブロックです
code body
クラスオブジェクトおよびインターフェース Version 180 | 静的およびインスタンス | 94
クラス内のインスタンス初期化コードはそのクラスからオブジェクトがインスタンス化されるたびに実行されますこれらのコードブロックはコンストラクタの前に実行されます
クラス用のコンストラクタを書き込みたくない場合インスタンス変数の初期化のためのインスタンス初期化コードブロックを使用可能ですしかしながら初期化をするには変数にデフォルト値を与えたりコンストラクタの本文を使用したりしてインスタンス初期化コードを使わない場合がほとんどでしょう
静的初期化コードは以下のキーワードstaticを伴って先行するコードのブロックです
static
code body
他の静的コードに類似して静的初期化コードはクラスの初回使用時に一度だけ初期化されます
一つのクラスは静的またはインスタンス初期化コードブロックのいずれかのナンバーを持てますそれらはコード本文内のどこにでも出現する可能性がありますJava内でと同様にファイル内で表示された順番にコードブロックは実行されます
静的最終変数を初期化するためおよび値のマップなど静的な情報を宣言するために静的初期化コードを使用可能です例
public class MyClass
class RGB
Integer red Integer green Integer blue
RGB(Integer red Integer green Integer blue) thisred = red thisgreen = green thisblue= blue
static MapltString RGBgt colorMap = new MapltString RGBgt()
static colorMapput(red new RGB(255 0 0)) colorMapput(cyan new RGB(0 255255)) colorMapput(magenta new RGB(255 0 255))
Apex プロパティApex プロパティは変数と似ていますがアクセスまたは返却する前にプロパティ値にスクリプトの内容を追加できますプロパティにはさまざまな使い方がありますまず変更の前にデータを検証できますまた他のメンバー変数値の変更などデータが変更される前にアクションを要求できますあるいは別のクラスなど別のソースから取得したデータを表示することもできます
プロパティの定義には一つまたは二つのコードブロックが含まれゲットアクセス機構とセットアクセス機構を表します
bull プロパティが読まれるとゲットアクセス機構内のコードが実行されますbull プロパティが新しい値に割り当てられるとセットアクセス機構内のコードが実行されます
ゲットアクセス機構だけを持ったプロパティは読み取り専用と考えられますセットアクセス機構だけを持ったプロパティは書き込み専用と考えられます両方のアクセス機構を持つプロパティは読み書き用です
クラスオブジェクトおよびインターフェース Version 180 | Apex プロパティ | 95
プロパティの宣言のためにクラスの本文内にて次の構文を使ってください
Public class BasicClass
Property declaration access_modifier return_type property_name get Get accessorcode block set Set accessor code block
この場合次のようになります
bull access_modifierがプロパティのアクセス変更子の場合は変数に適用可能なすべての変更子はプロパティにも適用可能です具体的にはpublicprivateglobalprotectedstaticvirtualabstractoverrideおよび transientですアクセス変更子についての詳細はAccess Modifiers (ページ 92)を参照してください
bull IntegerDoublesObjectなどreturn_typeはプロパティのタイプですIntegerDoublesObjectなど詳細はData Types (ページ 27)を参照してください
bull property_nameはプロパティ名です
例えば次のクラスはpropという名のプロパティを定義しますプロパティは公開ですプロパティはIntegerデータ型を戻します
public class BasicProperty public integer prop get return prop set prop = value
以下のコードセグメントは上記のクラスを呼び出しセットアクセス機構を実施します
BasicProperty bp = new BasicProperty() bpprop = 5 Calls set accessorSystemassert(bpprop == 5) Calls get accessor
次の点に注意してください
bull ゲットアクセス機構の本文は方法の本文に似ていますそれはプロパティ型の値を戻す必要がありますゲットアクセス機構を実行することは変数の値を読み取るのと同じことです
bull ゲットアクセス機構はリターンステートメント内で終わる必要がありますbull Salesforcecom はゲットアクセス機構が定義してしているオブジェクトの状態を変更しないことをお勧め
しますbull セットアクセス機構は戻り型が無効の方法に似ていますbull プロパティに値を割り当てると新しい値を与える引数によってセットアクセス機構が呼び出されますbull セットアクセス機構が呼び出されるとシステムは暗黙的引数をプロパティと同じデータ型のvalueと呼ば
れるセッターに渡しますbull プロパティはinterface上では定義できませんbull ApexプロパティはC内の対応物に基づいていて以下の違いを持っています
- プロパティは値のストレージを直接提供しますストレージ値のためにサポーティングメンバーを作成する必要はありません
- Apex内に自動プロパティを作成することが可能です詳細はUsing Automatic Properties (ページ 96)を参照してください
自動プロパティを使用する
プロパティはゲットまたはセットアクセス機構のコードブロック内に追加コードを要求しません代わりに自動プロパティを定義するためにゲットおよびセットアクセス機構のコードブロックは空白のままにし
クラスオブジェクトおよびインターフェース Version 180 | Apex プロパティ | 96
ておいてください自動プロパティによってデバッグと保守がより簡単なさらにコンパクトなコードを書くことが可能です読み取り専用読み書き用書き込み専用として宣言可能です以下の例は三つの自動プロパティの例を示しています
public class AutomaticProperty public integer MyReadOnlyProp get public doubleMyReadWriteProp get set public string MyWriteOnlyProp set
以下のコードセグメントはこれらのプロパティを実行します
AutomaticProperty ap = new AutomaticProperty() apMyReadOnlyProp = 5 コンパイルエラーが発生します not writable apMyReadWriteProp = 5 No errorSystemassert(MyWriteOnlyProp == 5) コンパイルエラーが発生します not readable
静的プロパティを使う
staticとしてプロパティが宣言された場合そのプロパティのアクセス機構方式は静的コンテキストで実行されますこれはそのアクセス機構がクラス内の非静的メンバー変数にアクセスしないことを意味します以下の例は静的およびインスタンスプロパティの両方を持つクラスを作成します
public class StaticProperty public static integer StaticMember public integerNonStaticMember public static integer MyGoodStaticProp getreturn MyGoodStaticProp The following produces a system error public static integer MyBadStaticProp returnNonStaticMember
public integer MyGoodNonStaticProp getreturn NonStaticMember
以下のコードセングメントは静的およびインスタンスプロパティを呼び出します
StaticProperty sp = new StaticProperty() システムエラーが発生します オブジェクトインスタンスの静的 変数にはアクセスできません spMyGoodStaticProp = 5
次の場合エラーは発生しません StaticPropertyMyGoodStaticProp = 5
プロパティアクセス機構上でアクセス変更子を使う
それ自身のアクセス変更子によってプロパティアクセス機構は定義可能ですアクセス機構がそれ自身のアスセス変更子を含んでいる場合この変更子はプロパティのアクセス変更子より優先します個別のアクセス機構のアクセス変更子はプロパティ上のアクセス変更子より限定的である必要があります例えばプロパティがpublicとして定義されている場合個別のアクセス機構はglobalとしては定義できません以下のクラス定義は追加の例です
global virtual class PropertyVisibility X is private for read and public for writepublic integer X private get set Y can be globally read but only written within aclass global integer Y get public set Z can be read within the class but onlysubclasses can set it public integer Z get protected set
インターフェースおよび拡張クラス
インタフェースはメソッドが実装されていないクラスのようなものですメソッドのシグネチャはありますが各メソッドの本文は空です インターフェースを使用するにはインターフェースに含まれるすべてのメソッドの本文を提供することによって別のクラスがインターフェースを実装する必要があります
クラスオブジェクトおよびインターフェース Version 180 | インターフェースおよび拡張クラス | 97
インターフェースは抽象化レイヤーをコードに提供できますインターフェースはメソッドの特定の実装をそのメソッドの宣言から分離しますこれによりアプリケーションに基づきメソッドを別個に実装できます
インターフェースの定義は新しいクラスの定義に似ています企業への顧客からと社員からの 2 種類の注文の例について考えますどちらもタイプは注文です割引をするメソッドが必要であるとします割引額は注文のタイプにより異なります
注文の一般的な概念をインターフェースとしてモデリングし顧客用および社員用に実装します次の例では注文の割引についてのみ示します
public class PurchaseOrders
一般的な注文の概要について定義するインターフェースpublic interface PurchaseOrder 他のすべての機能は除外Double discount()
顧客用のインターフェースの 1 つの実装public virtual class CustomerPurchaseOrder implementsPurchaseOrder public virtual Double discount() return 05 一律 5 の割引
従業員の注文は顧客の発注を拡張したものですが 割引率が異なりますpublic classEmployeePurchaseOrder extends CustomerPurchaseOrder public override Double discount() return 10 従業員であることにはメリットがあります割引率は 10
上記の例では次の点にご注意ください
bull インターフェースPurchaseOrderは汎用的なプロトタイプとして定義されていますインターフェース内で定義されているメソッドにはアクセス修飾子はなくそのシグネチャのみが含まれます
bull CustomerPurchaseOrderはこのインターフェースを実装しているためdiscountメソッドの定義を提供しなければなりませんJava においてはインターフェースを実装するすべてのクラスではインターフェースに含まれるすべてのメソッドを定義しなければなりません
bull 従業員用の注文は顧客用の注文を拡張します1 つのクラスから別のクラスに拡張するにはextendsキーワードを使用しますクラスは別のクラスを 1 つまでしか拡張できませんが1 つ以上のインターフェースを実装できます
新しいインターフェースを定義する場合新しいデータ型を定義することになりますそのインターフェース名は他のデータ型の名前を使用する場所であればどこででも使用できます型がインターフェースである変数を定義する場合それに割り当てるオブジェクトはインターフェースを実装するクラスのインスタンスまたはサブインターフェースデータ型でなければなりません
インターフェースは別のインターフェースを拡張できますクラスではインターフェースが別のインターフェースを拡張すると拡張元のインターフェースのすべてのメソッドとプロパティが拡張先のインターフェースでも利用できます
「クラスとキャスト」 (ページ 110)も参照してください
クラスが「管理-リリース済み」パッケージバージョンでアップロードされた後にインターフェースにメソッドを追加することはできません管理パッケージの詳細は「管理パッケージでのApexの開発 (ページ165)」を参照してください
クラスオブジェクトおよびインターフェース Version 180 | インターフェースおよび拡張クラス | 98
パラメータ化された型とインターフェースApex は通常静的に定型化されたプログラム言語でユーザは変数を使用する前に変数のデータ型を指定する必要がありますたとえば次の変数は Apex では適切です
Integer x = 1
xが始めに定義されていない場合次の変数は不正です
x = 1
リストマップおよびセットは Apex でパラメータ化されますApex が引数としてサポートするデータ型を採用しますこのデータ型はリストマップまたはセットの構造時に実際のデータ型と置き換える必要があります例
ListltStringgt myList = new ListltStringgt()
パラメータ化された型を使用すると構築時に実際のデータ型と置き換えられる一般的なデータ型パラメータでインターフェースを実装できます
次にパラメータ化されたインターフェースのシンタックスがどのように機能するかについての例を示しますこの例ではインターフェース Pairには2 つのタイプ変数 Tおよび Uがありますタイプ変数はインターフェースの本文で通常の型と同じように使用できます
public virtual interface PairltT Ugt T getFirst() U getSecond() void setFirst(T val)void setSecond(U val) PairltU Tgt swap()
次のインターフェース DoubleUpは Pairインターフェースを拡張します次のようにタイプ変数 Tを使用します
public interface DoubleUpltTgt extends PairltT Tgt
ヒント DoubleUpによって拡張するようにPairを virtualとして定義する必要があります
パラメータ化されたインターフェースの実装
パラメータ化されたインターフェースを実装するクラスはインターフェースのデータ型パラメータに引数としてデータ型を渡す必要があります
public class StringPair implements DoubleUpltStringgt private String s1 private String s2
public StringPair(String s1 String s2) thiss1 = s1 thiss2 = s2
public String getFirst() return thiss1 public String getSecond() return thiss2
public void setFirst(String val) thiss1 = val public void setSecond(String val) thiss2 = val
public PairltString Stringgt swap() return new StringPair(thiss2 thiss1)
クラスオブジェクトおよびインターフェース Version 180 | パラメータ化された型とインターフェース | 99
タイプ変数はクラスなどインターフェース宣言外に表示されることはありませんただしPairltString
Stringgtのように完全にインスタンス化されたタイプは他のデータ型が表示される Apex のどこでも使用できますたとえば次の変数は Apex では適切です
PairltString Stringgt y = xswap() DoubleUpltStringgt z = (DoubleUpltStringgt) y
この例ではコンパイラがクラス StringPairをコンパイルする場合クラスが DoubleUpltStringgtおよびPairltString Stringgtのすべてのメソッドを実行していることを確認する必要がありますそのためコンパイラはインターフェース PairltT Ugtの本文内の Tに String をUに String を代入します
DoubleUpltStringgt x = new StringPair(foo bar)
つまりクラスを正常にコンパイルするために次のメソッドプロトタイプをStringPairで実装する必要があります
String getFirst() String getSecond() void setFirst(String val) void setSecond(Stringval) PairltString Stringgt swap()
メソッドのオーバーロード
この例では次のインターフェースが使用されます
public interface OverloadedltTgt void foo(T x) void foo(String x)
インターフェース Overloadedは Apex で適切です名前は同じでパラメータが異なる 2 つ以上のメソッドを定義してメソッドをオーバーロードできますただしオーバーロードされたメソッドを呼び出す場合曖昧さがあってはいけません
インターフェースで指定された両方のメソッドプロトタイプを同時に実装するため次のクラスは正常にOverloadedインターフェースを実装します
public class MyClass implements OverloadedltStringgt public void foo(String x)
mが MyClassと指定されMyClassfooは一意の一致するメソッドであるため次は正常に実行されます
MyClass m = new MyClass() mfoo(bar)
oが OverloadedltStringgtに指定されofoo()の一致メソッドが 2 つありどちらも特定のメソッドに指定されないため次の例は正常に実行されませんコンパイラは2 つの一致メソッドのうちどちらを使用するか区別できません
OverloadedltStringgt o = m ofoo(bar)
パラメータ化されたリストによるサブタイプ
Apex ではタイプ Tが Uのサブタイプである場合ListltTgtは ListltUgtのサブタイプとなりますたとえば次の例は有効です
ListltStringgt slst = new ListltStringgt foo bar ListltObjectgt olst = slst
クラスオブジェクトおよびインターフェース Version 180 | パラメータ化された型とインターフェース | 100
ただしリストマップまたはセットなどパラメータ化されたタイプのインターフェイスで使用することはできません次の例は不正です
public interface IltTgt IltStringgt x = IltObjectgt y = x Compile error Illegalassignment from IltStringgt to IltObjectgt
カスタムイテレータイタレータは集合内のすべての項目をトラバースしますたとえばApex の whileループでループを終了する条件を定義し集合をトラバースするいくつかの方法つまりイタレータを提供する必要があります次の例ではループが実行されるごとに (count++)countが 1 ずつ増加します
while (count lt 11) Systemdebug(count) count++
Iteratorインターフェースを使用してループのリストをトラバースする指示のカスタムセットを作成できます通常SELECT文を使用して範囲を定義する Salesforcecom 外のソースにあるデータに役立ちます複数のSELECT文がある場合にイタレータを使用することもできます
カスタムイタレータの使用
カスタムイタレータを使用するにはIteratorインターフェースを実装する Apex クラスを作成する必要があります
Iteratorクラスには次インスタンスメソッドがあります
説明戻り値引数名前
コレクション内の別の項目がトラバースされている場合はtrueが返されそうでない場合はfalse
が返されます
BooleanhasNext
コレクション内の次の項目を返します任意next
Iteratorインターフェース内のすべてのメソッドは globalとして定義する必要があります
カスタムイタレータは whileループでのみ使用できます例
IterableString x = new IterableString(This is a really cool test)
while(xhasNext()) systemdebug(xnext())
イタレータは現在forループではサポートされていません
Iterable とカスタムイタレータの使用
カスタムイタレータとリストを使用しない場合Iterableインターフェースを使用してデータ構造を生成できます
Iterableインターフェースには次のメソッドがあります
クラスオブジェクトおよびインターフェース Version 180 | カスタムイテレータ | 101
説明戻り値引数名前
このインターフェースのイタレータへの参照を返します
イタレータクラスiterator
iteratorメソッドは globalとして定義する必要がありますデータ構造のトラバースに使用できるイタレータへの参照を作成します
次の例ではコレクションのカスタムイタレータの例を示します
global class CustomIterable implements IteratorltAccountgt ListltAccountgt accs get setInteger i get set public CustomIterable() accs = [SELECT id name numberofEmployeesFROM Account WHERE name = false] i = 0 global boolean hasNext() if(i gt= accssize())return false else return true global Account next() if(i == 8) i++ return nulli=i+1 return accs[i-1]
次で上記のコードを呼び出します
global class foo implements iterableltAccountgt global IteratorltAccountgt Iterator() returnnew CustomIterable()
次はイタレータを使用する一括処理ジョブです
global class batchClass implements DatabasebatchableltAccountgt global IterableltAccountgtstart(DatabasebatchableContext info) return new foo() global voidexecute(DatabasebatchableContext info ListltAccountgt scope) ListltAccountgt accsToUpdate =new ListltAccountgt() for(Account a scope) aname = true anumberOfEmployees = 69accsToUpdateadd(a) update accsToUpdate global void finish(DatabasebatchableContextinfo)
キーワード
Apex では次のキーワードをサポートしています
bull final
bull instanceof
bull super
bull this
bull transient
bull with sharingおよび without sharing
finalキーワードの使用finalキーワードは次のように使用できます
bull ファイナル変数には変数の宣言時またはコードの初期化時のいずれか 1 回のみ値を割り当てることができますこのいずれかで値を割り当てる必要があります
bull 静的なファイナル変数は静的初期化コードまたは定義時に変更できますbull メンバーファイナル変数は初期化コードブロックコンストラクタまたは他の変数の宣言と共に変更で
きます
クラスオブジェクトおよびインターフェース Version 180 | キーワード | 102
bull 定数を定義するには変数を staticおよび finalの両方に定義します (「定数 (ページ 41)」を参照してください)
bull ファイナルでない静的変数はクラスレベルでの状態の通信 (トリガ間の状態など) に使用しますしかし要求間で共有されることはありません
bull デフォルトではメソッドおよびクラスはファイナルとなりますfinalキーワードをクラスやメソッドの宣言では使用できませんつまり値をオーバーライドすることはできませんメソッドまたはクラスをオーバーライドするには virtualキーワードを使用します
instanceofキーワードの使用ランタイム時にオブジェクトが実際にある特定のクラスのインスタンスであることを確認するにはinstanceOf
キーワードを使用しますinstanceofキーワードは式でキーワードの右にあるターゲット型が左の式の宣言型の実行可能な代替物であることを確認する場合にのみ使用します
「クラスとキャスト例」の Reportクラスにおいて項目を CustomReportオブジェクトに再度キャストするために次のチェックを追加することができます
If (Reportsget(0) instanceof CustomReport) カスタムレポートオブジェクトに問題なく再度キャスト可能CustomReport c = (CustomReport) Reportsget(0) Else カスタムでないレポートに対する処理を記述
superキーワードの使用superキーワードは仮想クラスまたは抽象クラスから拡張されるクラスによって使用できますsuperを使用することによって親クラスのコンストラクタおよびメソッドを上書きできます
たとえば次の仮想クラスがあるとします
public virtual class SuperClass public String mySalutation public String myFirstNamepublic String myLastName
public SuperClass()
mySalutation = Mr myFirstName = Carl myLastName = Vonderburg
public SuperClass(String salutation String firstName String lastName)
mySalutation = salutation myFirstName = firstName myLastName = lastName
public virtual void printName()
Systemdebug(My name is + mySalutation + myLastName)
public virtual String getFirstName() return myFirstName
Superclassを拡張しprintNameメソッドを上書きする次のクラスを作成できます
public class Subclass extends Superclass public override void printName() superprintName() Systemdebug(But you can call me + supergetFirstName())
SubclassprintNameを呼び出す場合に期待される出力は My name is Mr Vonderburg But you cancall me Carlとなります
クラスオブジェクトおよびインターフェース Version 180 | instanceof キーワードの使用 | 103
superを使用してコンストラクタを呼び出すことができます次のコンストラクタを SubClassに追加します
public Subclass() super(Madam Brenda Clapentrap)
SubclassprintNameの期待される出力は My name is Madam Clapentrap But you can call meBrendaとなります
superキーワード使用のべストプラクティス
bull virtualクラスまたは abstractクラスから拡張しているクラスだけが superを使用できますbull overrideキーワードで指定されているメソッドでのみ superを使用できます
thisキーワードの使用thisキーワードには2 つの使用方法があります
thisをドット表記でかっこをつけずに使用し表示されるクラスの現在のインスタンスを表すことができますthisキーワードのこの形式はインスタンス変数とメソッドへのアクセスに使用します例
public class myTestThis
string s thiss = TestString
上記の例ではクラス testThisはインスタンス変数 sを宣言します初期化コードは thisキーワードを使用して変数に値を設定します
またコンストラクタチェーニングの実行でthisキーワードを使用することもできますコンストラクタチェーニングとは1 つのコンストラクタから別のコンストラクタをコールすることですこの形式ではthisキーワードをかっこと共に使用します例
public class testThis
このクラスの最初のコンストラクタstring 型のパラメータが必要ですpublic testThis(string s2)
このクラスの 2 つ目のコンストラクタパラメータは不要です このコンストラクタはthis キーワードを使用して 1 つ目のコンストラクタをコールします public testThis() this(None)
コンストラクタでのコンストラクタチェーニングの実行で thisキーワードを使用する場合コンストラクタの1 つ目の文に記述しなければなりません
transientキーワードの使用メモ transientキーワードはVisualforce コントローラとコントローラ拡張でのみ使用できます
クラスオブジェクトおよびインターフェース Version 180 | this キーワードの使用 | 104
transientキーワードは保存できずまたVisualforceページの一部として送信することもできないインスタンス変数の宣言に使用します例
Transient Integer currentTotal
変数を transientとして宣言すると表示状態のサイズを縮小しますtransientキーワードの一般的な使用事例にはVisualforce ページ上にあるページ要求を行っている間のみ必要な項目が挙げられますこの項目はページの表示状態の一部とすべきではなくまたリクエスト時に何度も再計算を行うため多くのシステムリソースが必要となります
Apex オブジェクトの中には自動的に transient と判断されるものもありますつまりその値はページの表示状態の一部として保存されません次のオブジェクトが含まれています
bull Savepointsbull PageReferencesbull XmlStreamクラスbull コレクションが自動的に transient とマーキングされるのはSavepoints のコレクションなどコレクションに
含まれているオブジェクトが自動的に transient とマーキングされている場合だけですbull SchemagetGlobalDescribeなどほとんどのオブジェクトがシステムメソッドにより自動的に生成されま
す
次の例にはVisualforceページとカスタムコントローラの両方が含まれてますページが更新されるごとに transient日付は再作成されるため[更新] ボタンをクリックすると日付が更新されます非 transient 日付には表示状態からシリアル化されなかった元の値が保持されるため変わりません
ltapexpage controller=ExampleControllergt T1 t1 ltbrgt T2 t2 ltbrgt ltapexformgtltapexcommandLink value=refreshgt ltapexformgt ltapexpagegt
public class ExampleController
DateTime t1 transient DateTime t2
public String getT1() if (t1 == null) t1 = Systemnow() return + t1
public String getT2() if (t2 == null) t2 = Systemnow() return + t2
with sharingまたは without sharingキーワードの使用Apex スクリプトは一般にシステムコンテキストで実行されますつまりスクリプト実行時に現在のユーザのプロファイルベースの権限項目レベルセキュリティおよび共有ルールは考慮されません
メモ このルールの唯一の例外はexecuteAnonymousコールと共に実行される Apex スクリプトですexecuteAnonymousは常に現在のユーザのフル権限を用いて実行されますexecuteAnonymousの詳細は「匿名ブロック」 (ページ 81)を参照してください
ルールが強制実行されるわけではないためApex を使用する開発者はプロファイルに基づく権限項目レベルのセキュリティ組織のデフォルトなどにより通常はユーザから隠されている重要データをうっかり公開することがないように注意しなければなりません特にWeb サービスについては注意が必要ですWeb サービスはプロファイルによって制限できますが初期化された後はシステムコンテキストで実行されます
クラスオブジェクトおよびインターフェース Version 180 | with sharing または without sharing キーワードの使用 | 105
多くの場合システムコンテキストは組織内のすべてのデータへのアクセスが必要なトリガWeb サービスなどに対してシステムレベルの運用の正しい動作を設定しますしかし特定の Apex クラスが現在のユーザに適用されている共有ルールを強制実行するように指定することもできます(共有ルールの詳細はSalesforcecomオンラインヘルプを参照してください)
メモユーザのプロファイルに基づく権限と項目レベルのセキュリティはApexスクリプトが組織内のすべての項目とオブジェクトを参照できることを保証するために常に無視されます特定の項目やオブジェクトがユーザから隠されている場合スクリプトの実行時にコンパイルでエラーが発生します
現在のユーザに適用されている共有ルールを強制実行するにはクラスの宣言時にwith sharingキーワードを使用します例
public with sharing class sharingClass
ここにコードを記述
現在のユーザに適用されている共有ルールを強制実行されないようにするにはクラスの宣言時に without
sharingキーワードを使用します例
public without sharing class noSharing
ここにコードを記述
with sharing も without sharing も使わずにクラスを宣言している場合現在の共有ルールが有効となりますつまりそのクラスが共有が強制実行されているクラスからコールされるとコールされたクラスでも共有が強制実行されます
内部クラスと外部クラスはどちらもwith sharingとして宣言できます共有設定は初期化コードコンストラクタメソッドなどクラスに含まれているすべてのコードに適用されますクラスは1 つのクラスを拡張または実装するとこの設定を親クラスから継承しますしかし内部クラスはコンテナクラスから共有設定を継承しません
例
public with sharing class CWith このクラスのすべてのコードは共有ルールが強制実行されます
Account a = [select ]
public static void m()
static
public c()
public without sharing class CWithout このクラスのすべてのルールは共有ルールを無視し コンテキストユーザが Modify All Data 権限を所有しているかのように動作しますAccount a = [select ]
public static void m()
CWith へのこのコールはコンテキストユーザに対する 共有ルールが強制実行される状態で動作しますコール
クラスオブジェクトおよびインターフェース Version 180 | with sharing または without sharing キーワードの使用 | 106
が完了すると コードの実行は without sharing モードに戻りますCWithm()
public class CInner このクラスのすべてのコードはこのコードを呼ぶコードと同じ 共有コンテキストで実行されます 内部クラスと外部クラスは分離されています
先ほどと同様にCWith へのこのコールはこの内部クラスを最初にコールしたクラスに関わらず コンテキストユーザに対する共有ルールが強制実行される状態で動作します コールが完了するとコードの実行はこの内部クラスをコールするのに使用された共有モードに戻りますCWithm()
public class CInnerWithOut exends CWithout このクラスは共有ルールを無視する親クラスを拡張しているため このクラスのすべてのコードは共有ルールを無視します
警告 with sharingとして宣言されたクラスがwithout sharingとして動作するスクリプトをコールしないという保証はありませんそのためクラスレベルのセキュリティは常に必要となりますさらにPriceBook2 を使用するすべての SOQL または SOSL クエリはwith sharingキーワードを無視します適用された共有ルールに関わらずすべての PriceBook レコードが返されます
現在のユーザの共有ルールを強制実行すると次のような影響があります
bull SOQL および SOSL クエリ1 つのクエリはシステムコンテキストで動作する場合より少ない行を返す場合があります
bull DML 操作現在のユーザに正しい権限が付与されていない場合操作が失敗する場合がありますたとえばユーザが組織内に存在する外部キー値を指定したものの現在のユーザにはそのキー値へのアクセス権が付与されていない場合などです
アノテーション
Apexアノテーションはメソッドまたはクラスが使用される方法を変更するものでJava のアノテーションと似ています
アノテーションは先頭が記号から始まり適切なキーワードがそれに続きますメソッドにアノテーションを追加するにはメソッド定義またはクラス定義の直前で指定します例
global class MyClass future Public static void myMethod(String a) 長い Apex コード
Apex では次のアノテーションをサポートしています
bull future
bull isTest
bull deprecated
Future
futureアノテーションを使用してメソッドを非同期に実行しますfutureを指定するとSalesforcecom に使用可能なリソースが存在するときにこのメソッドが実行されます
クラスオブジェクトおよびインターフェース Version 180 | アノテーション | 107
たとえば外部サービスへの非同期の Web サービスコールアウトを実行する際に futureアノテーションを使用できますアノテーションがない場合Web サービスコールアウトは Apex スクリプトを実行している同じスレッドから実行されコールアウトが完了するまでのかの処理は発生しません (同期処理)
futureアノテーションのあるメソッドは静的メソッドでなければならずvoid 型のみを返します
クラスのメソッドを非同期に実行するにはfutureアノテーションのあるメソッドを定義します例
global class MyFutureClass
future static void myMethod(String a Integer i) Systemdebug(Method called with +a + and + i) コールアウトを実行その他の長い実行コード
次のスニペットはメソッドがどのようにコールアウトを実行するかを指定します
future (callout=true) public static void doCalloutFromFuture() コールアウトを実行するコードの追加
メソッドがコールアウトを実行しないようにするには(callout=false)を指定します
futureアノテーションで定義されたメソッドをテストするにはstartTeststopTestコードブロックにメソッドを含むクラスを呼び出しますstartTestメソッド後に作成されたすべての非同期コールはシステムによって収集されますstopTestを実行する場合すべての非同期プロセスが同期して実行されます
futureアノテーションのあるメソッドには次のような制限事項があります
bull Apex 呼び出しあたりコールは最大 10 メソッド
メモ startTestブロックおよび stopTestブロックで呼び出された futureまたは executeBatch
などの非同期コールはキュー内ジョブ数の制限に対してカウントされません
bull futureアノテーションを含むメソッドはtestMethodのコンテキスト内にある場合100 件の SOQL クエリーを実行できます
bull Salesforcecom ライセンスあたりコールは 24 時間ごとに最大 200 メソッドbull 指定されたパラメータはプリミティブデータ型プリミティブデータ型の配列プリミティブデータ型のコ
レクションでなければなりませんbull futureアノテーションのあるメソッドはsObject またはオブジェクトを引数としてとることはできませんbull futureアノテーションを含むメソッドはVisualforceコントローラのgetMethodNameまたはsetMethodName
メソッド内でもコンストラクタ内でも使用できません
futureアノテーションを使用するすべてのメソッドはメソッドがコールされた順番に実行されるとは限らないため特に考慮する必要があります
futureアノテーションのあるメソッドを同様に futureアノテーションのあるメソッドからコールすることはできませんまたアノテーションを含む別のメソッドをコールしているアノテーションを含むメソッドからトリガをコールすることはできません
コールアウトの詳細は「Apex を使ったコールアウトの呼び出し (ページ 173)」を参照してください
クラスオブジェクトおよびインターフェース Version 180 | Future | 108
IsTest
isTestアノテーションを使用してアプリケーションのテストに使用するコードのみを含むクラスまたは個別のメソッドを定義しますisTestアノテーションはtestMethodとして宣言したメソッドの作成と似ています
メモ isTestで指定したクラスは1 MB という Apex スクリプトの組織内の上限には含まれませんfutureアノテーションのある個別のメソッドは組織の上限の制限を受けます詳細は「実行ガバナーと制限の理解」を参照してください
isTestとして定義されたすべてのクラスとメソッドは privateとして宣言する必要があります例
isTest private class MyTest
テストのメソッド
isTestとして定義されたクラスはインターフェースまたは enum 値とすることはできません
isTestとして定義されたクラスはForcecom runTests() API コールまたは Salesforcecom ユーザインターフェース ([Run Tests]ボタンを使用) からのみ起動できます別のクラスまたはトリガからはコールできません
Deprecated
deprecatedアノテーションを使用して今後のリリースの管理パッケージでは参照できないメソッドクラス例外列挙インタフェース変数を示すことができます管理パッケージのコードをリファクタリングする場合に役立ちます新しい登録者は破棄された要素を参照することはできませんが要素は既存の登録者および API 統合に機能し続けます
次のコードスニペットは破棄されたメソッドを示します同じシンタックスを使用してクラス例外列挙インターフェースまたは変数を破棄できます
deprecated このメソッドは deprecated です代わりに myOptimizedMethod(String a String b)を使用します public void myMethod(String a)
Apex 識別子を破棄する場合次のルールに注意してください
bull 非管理パッケージにはdeprecatedキーワードを使用するコードを含めることはできませんbull Apexの場合またはカスタムオブジェクトが破棄される場合破棄された識別子を参照するすべてのglobal
アクセス修飾子も破棄する必要があります署名入力引数またはメソッドが返す結果で破棄された種類を使用する global メソッドも破棄する必要がありますメソッドまたはクラスなど破棄された項目は最初はパッケージ開発者によって参照できます
bull webServiceメソッドおよび変数は破棄できませんbull enumは破棄できますが各 enum値は破棄できませんbull インターフェースは破棄できますがインターフェースの各メソッドは破棄できまさせんbull 抽象クラスは破棄できますが抽象クラスの各抽象メソッドは破棄できませんbull Apexのの項目が破棄されたパッケージをリリースした後deprecatedアノテーションを削除してApex識別
子の非推奨を取り消すことはできません
クラスオブジェクトおよびインターフェース Version 180 | IsTest | 109
パッケージバージョンの詳細は「管理パッケージでの Apex の開発 (ページ 165)」を参照してください
クラスとキャスト
通常すべての型情報は実行時に利用できますつまりApex はキャストを許可していますキャストとはあるクラスのデータ型を別のクラスのデータ型として割り当てることですただし割り当てるクラスが元のクラスの子である場合に限りますあるデータ型のオブジェクトを別のデータ型に変換する場合にキャストを使用します
次の例ではCustomReportが Reportクラスを拡張していますそのためそのクラスの子となっていますつまり親のデータ型 (Report) のオブジェクトを子のデータ型 (CustomReport) のオブジェクトにキャストできます
次のコードブロックではまずレポートオブジェクトのリストにカスタムレポートオブジェクトが追加されますその後カスタムレポートオブジェクトがレポートオブジェクトとして返されカスタムレポートオブジェクトとして再度キャストされます
Public virtual class Report
Public class CustomReport extends Report レポートオブジェクトのリストを作成Report[] Reports= new Report[5]
カスタムレポートオブジェクトを作成CustomReport a = new CustomReport()
カスタムレポートオブジェクトが Report クラスのサブクラスであるため カスタムレポートオブジェクトをレポートオブジェクトのリストに追加できますReportsadd(a)
次の手順は有効ではありませんなぜならコンパイラには返されているものが カスタムレポートであることが分からないからですどのような型が返されるかを通知するには キャストを使用しなければなりませんCustomReport c = Reportsget(0)
その代わりにカスタムレポートオブジェクトに再度キャストすることによりリストの最初の項目を取得しますCustomReport c = (CustomReport) Reportsget(0)
クラスオブジェクトおよびインターフェース Version 180 | クラスとキャスト | 110
図 7 キャスト例
さらにインターフェース型はサブインターフェースまたはそのインターフェースを実装しているクラス型にキャストできます
ヒント あるクラスが特定の型のクラスであることを確認するにはinstanceOfキーワードを使用します詳細は「instanceofキーワードの使用」 (ページ 103)を参照してください
クラスとコレクションリストとマップはsObjects で使用するのと同じようにクラスやインターフェースでも使用できますつまりユーザ定義のデータ型はマップの値のみで使用できキーでは使用できません同様にユーザ定義オブジェクトセットは作成できません
インターフェースのマップやリストを作成した場合インターフェースの子タイプはコレクションに入れることができますたとえばリストにインタフェース i1が含まれておりMyCが i1を実装している場合MyCをリストに含めることができます
コレクションキャストApex のコレクションには実行時に宣言型が存在するためApex ではコレクションキャストを許可しています
クラスオブジェクトおよびインターフェース Version 180 | クラスとコレクション | 111
コレクションはJava で配列をキャストするのと似た方法でキャストされますたとえばCustomerPurchaseOrderクラスが PurchaseOrderクラスの子である場合CustomerPurchaseOrder オブジェクトのリストを PurchaseOrder オブジェクトのリストに割り当てることができます
public virtual class PurchaseOrder
Public class CustomerPurchaseOrder extends PurchaseOrder
ListltPurchaseOrdergt POs = new PurchaseOrder[] ListltCustomerPurchaseOrdergt CPOs =new CustomerPurchaseOrder[] POs = CPOs
CustomerPurchaseOrderリストが PurchaseOrderリスト変数に割り当てられるとCustomerPurchaseOrder オブジェクトのリストに再度キャストすることができますこれはそのインスタンスが最初はCustomerPurchaseOrder のリストとしてインスタンス化されたためですこのようにインスタンス化されたPurchaseOrder オブジェクトのリストはPurchaseOrder オブジェクトのリストに CustomerPurchaseOrder オブジェクトのみが含まれている場合でもCustomerPurchaseOrder オブジェクトのリストにキャストできません
CustomerPurchaseOrders オブジェクトのみを含む PurchaseOrder リストのユーザ が PurchaseOrderの非CustomerPurchaseOrder サブクラス (InternalPurchaseOrderなど) を挿入しようとすると実行時に例外が発生しますこれはApex には実行時に宣言型が存在するためです
メモ マップの動作もマップの値側からみるとリストと同様ですマップ A の値側をマップ B の値側にキャスト可能でキータイプが同じである場合マップ A はマップ B にキャストできます実行時に特定のマップのキャストが有効でない場合ランタイムエラーが発生します
Apex クラスと Java クラスの違い
次にApex と Java クラスの主な違いについて示します
bull 内部クラスとインターフェースは外部クラスの 1 つ下のレベルでのみ宣言できますbull 静的メソッドと変数は内部クラスではなくトップレベルクラスでのみ宣言できますbull 内部クラスは静的Java内部クラスのように機能しますがstaticキーワードを要求しません内部クラス
は外部クラスのようにインスタンスメンバー変数を持つことができますが thisキーワードを使った 外部クラスのインスタンスへの暗黙的ポインタはありません
bull デフォルトのアクセス修飾子は privateですつまりメソッドまたは変数は定義された Apex クラス内からのみアクセス可能ですアクセス修飾子を指定しない場合メソッドや変数は privateとなります
bull メソッドまたは変数にアクセス修飾子を指定しない場合はprivateアクセス修飾子を指定した場合と同じ意味となります
bull publicアクセス修飾子はメソッドまたは変数がこのアプリケーションまたは名前空間内のすべての Apexで使用可能なことを意味します
bull globalアクセス修飾子はメソッドまたは変数が同じアプリケーション内の Apex スクリプトだけではなくクラスへのアクセス権を付与されたすべてのApexスクリプトで使用可能なことを意味しますこのアクセス修飾子はForcecom Web サービス API やその他の Apex スクリプトのいずれかでアプリケーション外から参照する必要があるメソッドで使用しますメソッドまたは変数をglobalとして宣言した場合それを含むクラスも globalとして宣言する必要があります
bull デフォルトではメソッドおよびクラスはファイナルとなります
- virtual定義修飾子は拡張やオーバーライドを許可します
クラスオブジェクトおよびインターフェース Version 180 | Apex クラスと Java クラスの違い | 112
- overrideキーワードは基本クラスメソッドをオーバーライドするメソッドで明示的に使用する必要があります
bull インターフェースメソッドには修飾子はなく常に global となりますbull 例外クラスは例外または別のユーザ定義例外への拡張が必要です
- 例外クラス名の末尾にはexceptionをつけなければなりません- 例外クラスは 4 つの暗黙的なコンストラクタが組み込まれていますが追加することもできます
詳細は「例外クラス」 (ページ 315)を参照してくださいbull クラスとインターフェースはトリガや匿名ブロック内で定義できますがローカルとしてのみ定義できます
クラス定義作成
Salesforcecom でクラスを作成する手順は次のとおりです
1 アプリケーションで[設定] [開発] [Apex クラス] をクリックします2 [New] をクリックします3 [バージョン設定]をクリックしてこのクラスで使用するApexおよびAPIのバージョンを指定します組織
がAppExchangeから管理パッケージをインストールした場合このクラスで使用する各管理パッケージのバージョンも指定できます通常はすべてのバージョンについてデフォルト値を使用してくださいデフォルト値ではApexおよびAPIについても各管理パッケージについてもクラスを最新バージョンに関連付けます最新バージョンのパッケージのものとは異なるコンポーネントや機能にアクセスする場合は管理パッケージの古いバージョンを指定することもできます古いバージョンのApexおよびAPIを指定して特定の動作を維持できます
4 [内容]テキストボックスでそのクラスのApexを入力します1 つのクラスは最大100000文字までです5 [保存] をクリックし変更を保存してクラスの詳細画面に戻るか[適用] をクリックし変更を保存してク
ラスの編集を続行します作成したApexスクリプトはクラスに保存する前に間違いなくコンパイルする必要があります
[WSDL からの生成] をクリックしてWSDL から自動的にクラスを生成することもできます「SOAP サービス WSDL ドキュメントからのクラスの定義 (ページ 174)」を参照してください
いったん保存するとクラスはその他の Apex スクリプトからクラスメソッドや変数を介して呼び出すことができます
メモ 下位互換性を持たせるためクラスはApex および API の特定のバージョンのバージョン設定とともに保存されますApex クラスがインストール済みの管理パッケージ内でカスタムオブジェクトなどのコンポーネントを参照する場合クラスが参照する各管理パッケージのバージョン設定も同時に保存されますまたクラスは最後にコンパイルされて以降依存するメタデータに変更がない限りisValidフラグを trueに設定して保存しますオブジェクトや項目の説明の編集などの表面的な変更も含めクラスで使用されているオブジェクト名や項目に変更があった場合またはこのクラスを呼び出すクラスに変更があった場合にはisValidフラグが falseに設定されますトリガまたは Web サービスコールによってクラスが呼び出されるとコードが再コンパイルされエラーが存在する場合にはユーザに通知されますエラーがない場合はisValidフラグが trueにリセットされます
クラスオブジェクトおよびインターフェース Version 180 | クラス定義作成 | 113
Apex クラスエディタ
VisualforceまたはApexを編集するときVisualforce開発モードフッターでまたは設定から次の機能を持つエディタを使用できます
構文の強調表示エディタはキーワードとすべての関数および演算子について自動的に構文を強調表示します
検索 ( )
検索により現在のページクラスまたはトリガの中のテキストを検索できます検索を使用するには[検索]テキストボックスに文字列を入力し[次を検索] をクリックします
bull 検出した検索文字列を他の文字列に置き換えるには[置換]テキストボックスに新しい文字列を入力しそのインスタンスだけを置き換える場合は [置換] をクリックしそのインスタンスとそれ以外にそのページクラスまたはトリガに出現する検索文字列のすべてのインスタンスを置き換える場合は[すべて置換] をクリックします
bull 検索操作で大文字小文字を区別するには[大文字と小文字を区別する] オプションをオンにしますbull 検索文字列として正規表現を使用するには[正規表現]オプションをオンにします正規表現はJavaScript
の正規表現規則に従います正規表現を使った検索では折り返しされて複数行になる文字列も検索できます
正規表現で検出した文字列を置換操作で使用する場合検出した検索文字列から得られる正規表現のグループ変数 ($1$2など) をバインドすることもできますたとえばltH1gtタグを ltH2gtタグで置き換え元の ltH1gtの属性はすべてそのままにするにはltH1(s+)()gtを検索しそれを ltH2$1$2gtで置き換えます
指定行に移動 ( )
このボタンにより指定した行番号を強調表示できますその行が現在表示されていない場合はエディタがその行までスクロールします
元に戻す ( ) またはやり直し ( )
[元に戻す] を使用して編集動作を取り消し[やり直し] により元に戻した編集動作をやり直します
フォントサイズドロップダウンリストからフォントサイズを選択しエディタに表示される文字のサイズを制御します
行と列の位置
カーソルの行と列の位置はエディタ下部のステータスバーに表示されますこれは[指定行に移動] ( )とともに使用しエディタ内をすばやく移動できます
行と文字のカウント行と文字の合計数はエディタ下部のステータスバーに表示されます
名前付け規則Salesforcecom は名前付けには次の Java 標準をお勧めしていますその標準ではクラス名は大文字から始まりメソッドは小文字の動詞から始まり変数名は意味を持つものにするという規則です
クラスオブジェクトおよびインターフェース Version 180 | 名前付け規則 | 114
同じクラスのクラスとインターフェースに同じ名前をつけることはできません外部クラスと内部クラスに同じ名前をつけることもできませんしかしメソッドと変数はクラス内に独自の名前空間があるためこの 3 つのタイプの名前は競合しません特にクラス内の変数メソッドクラスに同じ名前をつけることは有効です
名前のシャドウイングメンバー変数は特に関数の引数においてローカル変数でシャドウイングされますこれにより標準 Java 形式のメソッドやコンストラクタは次のように処理されます
Public Class Shadow String s Shadow(String s) thiss = s 同じ名前でも問題なしsetS(String s) thiss = s 同じ名前でも問題なし
1 つのクラスのメンバー変数は親クラスの同じ名前のメンバー変数をシャドウイングできます異なるトップレベルクラスの 2 つのクラスが異なるチームによって記述されている場合は有効ですたとえば一方にはクラス C への参照が含まれており親クラス P のメンバー変数 M (C のメンバー変数と同じ名前) へアクセスしたいとします参照はまず P への参照から割り当てます
静的変数はクラス階層間でシャドウイングできますそのためP が静的変数 S を定義するとサブクラス C も静的変数 S を宣言できますC 内の S への参照はその静的変数を参照しますP の静的変数を参照するには構文 PS を使用する必要があります
静的クラス変数はクラスインスタンスを通じて参照することはできません本来の変数名自体 トップレベルクラスファイル内 またはクラス名をつけたプレフィックスを使用して参照しなければなりません例
public class p1 public static final Integer CLASS_INT = 1 public class c p1c c= new p1c() 無効 Integer i = cCLASS_INT 正しい記述Integer i = p1CLASS_INT
クラスセキュリティ
ユーザプロファイルに基づいて特定の最上位レベルの でメソッドを実行できるユーザを指定できますトリガーではなくてApex上にだけセキュリティの設定が可能な点に留意ください
クラス一覧ページから Apex クラスのセキュリティを設定する手順は次のとおりです
1 [設定] [開発] [Apex クラス] をクリックします2 制限するクラス名の横にある [セキュリティ] をクリックします3 [選択可能なプロファイル] リストから有効にするプロファイルを選択し[追加] をクリックします4 [有効にされたプロファイル] リストから無効にするプロファイルを選択し[取り消し] をクリックします5 [保存] をクリックします
プロファイルの詳細ページから Apex クラスのセキュリティを設定する手順は次のとおりです
1 [設定] [ユーザの管理] [プロファイル] をクリックします2 変更するプロファイルの名前をクリックします3 [有効にされた Apex クラスアクセス] 関連リストから[編集] をクリックします4 [利用可能な Apex クラス] リストから有効にする Apex クラスを選択し[追加] をクリックします5 [有効にされた Apex クラス] リストから無効にする Apex クラスを選択し[削除] をクリックします
クラスオブジェクトおよびインターフェース Version 180 | 名前のシャドウイング | 115
6 [保存] をクリックします
名前空間プレフィックス
アプリケーションは名前空間プレフィックスの使用をサポートしています名前空間プレフィックスは管理された Forcecom AppExchange で使用されカスタムオブジェクトと項目名を他の組織で使用されているものと区別するために使用します開発者がグローバルで一意な名前空間プレフィックスを登録しAppExchangeレジストリに登録すると開発者の管理パッケージのカスタムオブジェクトおよび項目名への外部参照は次のような長い形式となります
namespace_prefix__obj_or_field_name__c
この完全修飾名はSOQL 文SOSL 文Apexでクラスが「管理済み」に設定されると更新が煩雑であるためApex はスキーマ名のデフォルトの名前空間をサポートしていますID を見るとパーサーは現在のオブジェクトの名前空間であると考え指定されていない限り他のすべてのオブジェクトと項目の名前空間であると判断しますその結果格納されているクラスは同じアプリケーション名前空間で定義されているオブジェクトに対して obj_or_field_name__cを使用してカスタムオブジェクトと項目名を直接参照します
ヒント AppExchange から組織にインストールされた管理パッケージのカスタムオブジェクトと項目を参照する場合のみ名前空間プレフィックスを使用します
メソッドの起動での名前空間の使用管理パッケージで定義されたメソッドを起動するにはApex は次の形式の完全修飾識別子を許可します
namespace_prefixclassmethod(args)
組み込み静的クラスとユーザ定義クラスとのあいまいさをなくすために特別な名前空間 Systemを使用します(SystemSystemdebug()) など
System名前空間プレフィックスがないと次に示すとおりMathや Systemなどのシステム静的クラス名が同じ名前ののユーザ定義クラスでオーバーライドされてしまいます
ヒント AppExchange から組織にインストールされた管理パッケージのメソッドを起動する場合のみ名前空間プレフィックスを使用します
名前空間クラス変数名の優先度ローカル変数クラス名名前空間が同じ識別子を使用することは仮定上可能であるためApex パーサーは次のように name1name2[]nameN形式の式を評価します
1 パーサーはまず name1が name2から nameNを項目参照として持つローカル変数であると仮定します2 最初の仮定が真でない場合パーサーは name1がクラス名でありname2が name3から nameNを項目参照と
して持つ静的変数名であると仮定します3 2 つ目のの仮定が真でない場合パーサーは name1が名前空間名name2がクラス名name3が静的変数名
でありname4から nameNが項目参照であると仮定します
クラスオブジェクトおよびインターフェース Version 180 | 名前空間プレフィックス | 116
4 3 つ目の仮定も真でない場合はパーサーはエラーを返します
式が 1 組のかっこで終了する場合 (name1name2[]nameMnameN()など)Apex パーサーは式を次のように評価します
1 パーサーはまず name1が name2から nameMを項目参照として持つローカル変数nameNがメソッド呼び出しであると仮定します
2 最初の仮定が真でない場合次の処理を行います
bull 式に識別子が 2 つしか含まれていない場合 (name1name2())パーサーはname1がクラス名で name2がメソッド呼び出しであると仮定します
bull 式に識別子が 3 つ以上含まれている場合パーサーは name1がクラス名name2が name3から nameMを項目参照として持つ静的変数名nameNがメソッド呼び出しであると仮定します
3 2 つ目のの仮定が真でない場合パーサーは name1が名前空間名name2がクラス名name3が静的変数名でありname4から nameMが項目参照nameNがメソッド呼び出しであると仮定します
4 3 つ目の仮定も真でない場合はパーサーはエラーを返します
ただしクラス変数については Apex はメンバー変数の参照にドット表記を使う場合もありますそれらのメンバー変数は他のクラスインスタンスを参照することもまた項目名への参照 (外部キーのアクセスのためなど)に独自のドット表記ルールを持つ sObject を参照することもあります
式に sObject 項目を入力すると式の残りは sObject ドメインにとどまりますつまりsObject 項目は Apex 式を再度参照することはできません
たとえば次のクラスがあるとします
public class c c1 c1 = new c1() class c1 c2 c2 class c2 Account a
その場合次の式はすべて有効です
cc1c2aname cc1c2aownerlastNametoLowerCase() cc1c2ataskscc1c2acontactssize()
型の解決と型のシステム名前空間システム型はローカルまたは他のクラスで定義されたユーザ定義型を解決しなければならないためApex パーサーは次のように型を評価します
1 型参照 TypeNではパーサーはまずその型をスカラー型として参照します2 TypeNが見つからない場合パーサーはローカルで定義された型を参照します3 そこでも TypeNが見つからない場合パーサーはその名前のクラスを参照します4 そこでも TypeNが見つからない場合パーサーは sObjects などのシステム型を参照します
型 T1T2はトップレベルクラス T1の内部型 T2または名前空間 T1のトップレベルクラス T2のいずれかを意味します (優先度はこの順序のとおり)
クラスオブジェクトおよびインターフェース Version 180 | 型の解決と型のシステム名前空間 | 117
バージョン設定
下位互換性を持たせるためクラスおよびトリガは特定の Salesforcecom API バージョンのバージョン設定とともに保存されますApexクラスまたはトリガがインストール済みの管理パッケージ内でカスタムオブジェクトなどのコンポーネントを参照する場合クラスが参照する各管理パッケージのバージョン設定も同時に保存されますApexAPIおよび管理パッケージのコンポーネントが次のリリースバージョンにアップグレードされた場合でもクラスまたはトリガは特定の既知の動作のバージョンにバインドされたままになります
インストール済みパッケージのバージョン設定を行うとインストール済みパッケージの Apex コードの公開されるインターフェースおよび動作が決まりますこれによりコードが廃止される前のバージョンのパッケージをインストールした場合最新バージョンのインストールパッケージで廃止される場合がある Apex を継続して参照できます
通常は最新のSalesforcecom APIバージョンの各インストールパッケージバージョンを参照しますSalesforcecomAPI バージョンを指定せずに Apex クラスまたはトリガを保存するとクラスまたはトリガはデフォルトで最新のインストールバージョンと関連付けられます管理パッケージのバージョンを指定せずに管理パッケージを参照する Apex クラスまたはトリガを保存する場合クラスまたはトリガはデフォルトで管理パッケージの最新のインストールバージョンに関連付けられます
クラスおよびトリガの Salesforcecom API バージョン設定クラスまたはトリガに Salesforcecom API および Apex のバージョンを設定する手順は次のとおりです
1 クラスまたはトリガのいずれかを編集して[バージョン設定] をクリックします2 Salesforcecom API のバージョンを選択します このバージョンはクラスまたはトリガに関連付けられてい
る Apex のバージョンでもあります3 [保存] をクリックします
メソッドコールのパラメータとしてオブジェクトを Apex クラスの C1 から C2 に渡しC2 では SalesforcecomAPI のバージョン設定により異なる項目が公開された場合オブジェクトの項目は C2 のバージョン設定によって制御されます
次の例を使用してテストクラス C1 のメソッドからクラス C2 の insertIdeaメソッドを呼び出した後に [カテゴリ]項目が nullに設定されます[カテゴリ]項目はバージョン 130 の API では使用できないためです
最初のクラスは Salesforcecom API バージョン 130 を使用して保存されます
このクラスは Salesforce API バージョン 130 を使用して保存されます バージョン 130 にはIdeacategories 項目のグローバルクラス C2 は含まれていません global Idea insertIdea(Idea a) insert a カテゴリ項目は挿入時 Null に設定されます
新しいアイデアを取得します Idea insertedIdea = [SELECT title FROM Idea WHERE Id =aid]
return insertedIdea
次のクラスは Salesforcecom API バージョン 160 を使用して保存されます
isTest このクラスはバージョン設定によって API バージョン 160 にバインドされます private classC1 static testMethod void testC2Method() Idea i = new Idea() iCommunityId =09aD000000004YCIAY iTitle = Testing Version Settings ibody = Categories field isincluded in API version 160 icategories = test
クラスオブジェクトおよびインターフェース Version 180 | バージョン設定 | 118
C2 c2 = new C2() Idea returnedIdea = c2insertIdea(i) 新しいアイデアを取得します IdeaideaMoreFields = [SELECT title categories FROM Idea WHERE Id = returnedIdeaid]
このクラスで作成されたオブジェクトのカテゴリ項目が null でないことを確認しますSystemassert(icategories = null) assert that the categories field created in C2 isnull Systemassert(ideaMoreFieldscategories == null)
Apex クラスおよびトリガのパッケージバージョンの設定クラスまたはトリガのパッケージバージョン設定を定義する手順は次のとおりです
1 クラスまたはトリガのいずれかを編集して[バージョン設定] をクリックします2 クラスまたはトリガによって参照される各管理パッケージの [バージョン]を選択します管理パッケージの
このバージョンはより新しいバージョンの管理パッケージがインストールされてもバージョン設定を手動で更新しない限りクラスまたはトリガによって引き続き使用されますインストール済み管理パッケージを設定リストに追加するには使用可能なパッケージのリストからパッケージを選択しますリストはクラスまたはトリガにまだ関連付けられていないインストール済み管理パッケージがある場合にのみ表示されます
3 [保存] をクリックします
パッケージバージョン設定を使用する場合は次のことに注意してください
bull 管理パッケージのバージョンを指定せずに管理パッケージを参照するApexクラスまたはトリガを保存する場合Apex クラスまたはトリガはデフォルトで管理パッケージの最新のインストールバージョンに関連付けられます
bull パッケージをクラスまたはトリガで参照している場合は管理パッケージのバージョン設定は [削除] できません[連動関係の表示] を使用してクラスまたはトリガから参照されている管理パッケージがどこにあるか検索できます
クラスオブジェクトおよびインターフェース Version 180 | Apex クラスおよびトリガのパッケージバージョンの設定 | 119
第 5 章
Apex デザインパターン
すべてのプログラム言語同様開発者は良いデザインパターンまたは悪いデザインパターンを使用できますこの章ではベストプラクティスについて説明し共通の不備について示しながら2 つのデザインパターンの違いを示します
トリガと一括要求
一般的な開発の不備はトリガの呼び出しに複数のレコードが含まれないことが想定されますApexトリガは一括で操作するよう最適化されています定義によっては開発者が一括操作をサポートするロジックを記述する必要があります
エラーが発生するプログラミングパターンの例を次に示しますトリガ呼び出しの間取り込まれるレコードは1 件のみと想定します多くのユーザインターフェースイベントはサポートされますがForcecom Web servicesAPI または Visualforce を使用して呼び出された一括操作はサポートされません
trigger MileageTrigger on Mileage__c (before insert before update) user c = [SELECT IdFROM user where mileageid__c =triggernew[0]id]
エラーが発生するもう 1 つのプログラミングパターンの例を次に示しますトリガ呼び出しの間取り込まれるレコードは 20 件未満と想定します要求に 20 件を超えるレコードが取り込まれるとトリガはトリガ内 20件の SELECT 文の SOQL クエリーの制限を超えます
trigger MileageTrigger on Mileage__c (before insert before update) for(mileage__c m triggernew) user c = [SELECT Id FROM user where mileageid__c =mid]
ガバナー制限の詳細は「実行ガバナーと制限の理解」を参照してください
次の例ではガバナー制限を重視しトリガの一括処理をサポートする適切なパターンを示します
Trigger MileageTrigger on Mileage__c (before insert before update) setltIDgt ids =TriggernewkeySet() listltusergt c = [SELECT Id FROM user WHERE mileageid__c in ids]
このパターンはTriggernewコレクションをセットに渡し単一の SOQL クエリのセットを使用してトリガの一括処理を行いますこのパターンはSOQL クエリの数を宣言しますが要求内のすべてのレコードをすべて取得します
一括プログラムのデザインのベストプラクティス
次はデザインパターンのベストプラクティスです
bull コレクションにレコードを追加しそれらのコレクションに対して DML 操作を実行することによってデータ操作言語 (DML) の数を最小化します
bull レコードを処理しセットを生成することによって SOQL 文を最小化しますIN句で使用される 1 つのSOQL 文に置き換えることができます
Apex デザインパターン Version 180 | トリガと一括要求 | 121
第 6 章
Apex のテスト
ここではApex のテストに Forcecom プラットフォームで使用できるツールのほかテストの概要について説明します
トピック
bull Apex のテストについてbull Apex のテストについてbull Apex のユニットテストbull Apex のユニットテストbull ユニットテストメソッドの実行bull ユニットテストメソッドの実行bull ベストプラクティスのテストbull ベストプラクティスのテストbull テストの例bull テストの例
Apex のテストについて
テストは長期間の開発を正常に行うためにキーとなるもので開発プロセスの重要な部分を占めますテストベースの開発プロセスつまりコード開発と同じ回数行うテスト開発を使用することを強くお勧めします
Apex テストの理由アプリケーションが正常に機能するために特にアプリケーションが顧客に配布される場合はテストを行うことが重要ですアプリケーションが期待された通りに機能すること予期しない動作がないことが確認されれば顧客の信頼度が向上します
アプリケーションのテストには 2 種類あります1 つは Salesforcecomユーザインターフェースと使用したテストですこれは重要ですがユーザインターフェースを使用してあまりテストを行わない場合アプリケーションの使用状況ケースのすべてを取得するわけではありません一括機能についてテストする必要もありますForcecom Web サービス API または Visualforce 標準セットコントローラを使用している場合最大 200 件のレコードがコードを通過できます
アプリケーションはめったに完了しません機能を変更または拡張する追加リリースがあります包括的テストを行う場合回帰に新しい機能を導入することができます
またForcecom AppExchange 向けにコードを展開またはパッケージ化する前に次の点を実行する必要があります
bull Apex スクリプトの75がユニットテストの適用範囲でかつすべてのテストは正しく完了します
次の点に注意してください
- 運用組織に展開する場合組織の名前空間内の各ユニットテストが行われます- Systemdebugへのコールはユニットテストの Apex コードの範囲の一部としてカウントされません- Apex コードの 75 だけをテストでカバーする必要がある場合フォーカスはカバーされるコードの割合
にあってはいけません代わりに正のケースや負のケース大量のレコードや単一レコードなどアプリケーションのすべての使用ケースがカバーされていることを確認してくださいコードの 75 以上がユニットテストにカバーされます
bull すべてのトリガについていくつかのテスト適用範囲ありますbull すべてのクラスとトリガは正常にコンパイルされます
メモ Systemdebugへのコールはユニットテストの Apex コードの範囲の一部としてカウントされません
Salesforcecom は組織内のユニットテストを Apex スクリプトで実行しサービスアップグレードの結果として動作が変更されていないことを確認します
Apex のテストの対象Salesforcecom は次についてテストを作成することをお勧めします
単一アクション単一レコードが適切で期待される結果を生成することを確認するテスト
Apex のテスト Version 180 | Apex のテストについて | 123
一括アクションすべての Apex スクリプトがトリガクラスまたは拡張であっても1 から 200 件のレコードについて呼び出されます単一レコードのケースだけでなく一括ケースについてもテストする必要があります
正の動作期待される動作がすべての期待される順列で行われることつまりユーザが正しく入力し制限を超えていないことを確認するテスト
負の動作将来の日付を追加できない負の数量を指定できないなどアプリケーションに制限がある場合があります負のケースについてテストし制限のケース内で正のケースと同様エラーメッセージが適切に表示されることを確認する必要があります
制限ユーザコード内で使用する sObjects に対するアクセス権が制限されているユーザが期待される動作を行えるかどうか (コードを実行できるかエラーメッセージを受信するか) についてのテスト
メモ 条件演算子および 3 項演算子は肯定ブランチおよび否定ブランチの両方が実行されない限り実行されるとはみなされません
テスト作成の詳細は「テストの例 (ページ 129)」を参照してください
Apex のユニットテスト
強固な開発を促進するためにエラーのないコードApex はユニットテストの作成および実行をサポートしますユニットテストは特定のコードが適切に動作しているかを確認するクラスメソッドですユニットテストは引数をとらずデータをデータベースにコミットせず電子メールを送信せずメソッド定義で testMethod
キーワードを使用してフラグを立てます
例
public class myClass static testMethod void myTest() code_block
メモ Web サービスコールアウトのテストに Test メソッドは使用できませんWeb サービスのコールアウトは非同期ですが非ニットテストは同期です
runAsメソッドの使用一般にApex スクリプトはすべてシステムモードで実行され現在のユーザの権限やレコード共有は考慮されませんシステムメソッドrunAsを使用してユーザコンテキストを既存のユーザまたは新規ユーザに変更するテストメソッドを作成したり特定バージョンの管理パッケージのコードを使用して実行したりできますユーザとして実行する場合ユーザのレコード共有のすべてが適用されますrunAsはテストメソッドでのみ使用できます元のシステムコンテキストはすべてのrunAsテストメソッドが完了した後で再開されますrunAs
メソッドの使用およびパッケージバージョンのコンテキスト指定の詳細は「パッケージバージョンの動作のテスト (ページ 169)」を参照してください
Apex のテスト Version 180 | Apex のユニットテスト | 124
メモ ユーザを指定する runAsへのコールは 20 件のみトランザクションで実行できます
次の例では新しいテストユーザーが作成されコードはユーザーの権限およびレコードアクセス権限によってを持つユーザーとして実行されます
public class TestRunAs public static testMethod void testRunAs() テストデータを設定 このコードはシステムユーザーとして実行
Profile p = [select id from profile where name=Standard User] User u = new User(alias =standt email=standardusertestorgcom emailencodingkey=UTF-8 lastname=Testinglanguagelocalekey=en_US localesidkey=en_US profileid = pIdtimezonesidkey=AmericaLos_Angeles username=standardusertestorgcom)
SystemrunAs(u) 次のコードはユーザー u として実行 Systemdebug(Current User +UserInfogetUserName()) Systemdebug(Current Profile + UserInfogetProfileId())
複数の runAsメソッドをネストすることができます例
public class TestRunAs2
public static testMethod void test2()
Profile p = [SELECT Id FROM profile WHERE name=Standard User] User u2 = new User(alias= newUser email=newusertestorgcom emailencodingkey=UTF-8 lastname=Testinglanguagelocalekey=en_US localesidkey=en_US profileid = pIdtimezonesidkey=AmericaLos_Angeles username=newusertestorgcom)
SystemrunAs(u2) 次のコードはユーザー u2 として実行しますSystemdebug(Current User +UserInfogetUserName()) Systemdebug(Current Profile + UserInfogetProfileId())
次のコードはユーザー u3 として実行します
User u3 = [select id from user where username=newusertestorgcom] SystemrunAs(u3) Systemdebug(Current User + UserInfogetUserName()) Systemdebug(Current Profile + UserInfogetProfileId())
ここで追加コードはユーザー u2 として実行します
runAs使用のベストプラクティス
次の項目では特定ユーザとして実行する runAsで指定されたユーザーに割り当てられた権限を使用します
bull ダイナミック Apexbull with sharingまたは without sharingを使用するメソッドbull 共有レコード
元の権限はrunAsが下記を完了後にリセットされます
runAsメソッドはユーザライセンスの制限を無視します組織に追加ユーザライセンスがない場合でもrunAs
で新しいユーザを作成できます
Apex のテスト Version 180 | runAs メソッドの使用 | 125
LimitsstartTestおよび stopTestの使用Limits メソッドはトリガWeb サービスメソッドなど実行されているコンテキストに対する特定の制限を返します
各メソッドには 2 つのバージョンがあります一方のバージョンのメソッドは現在のコンテキストで使用されているリソースの数を返しもう一方のバージョンは limit という用語を使用し該当するコンテキストに使用できるリソースの合計を返しますたとえばgetCalloutsは現在のコンテキストで処理されている外部サービスへのコールアウト数を返しgetLimitCalloutsは指定されたコンテキストで使用できるコールアウト数の合計を返します
Limits メソッドのほかstartTestメソッドおよび stopTestメソッドを使用してコードがガバナー制限にどれくらい近づいているかを確認します
startTestメソッドはテストが実際に開始する場合のテストコード内のポイントをマークします それぞれのtestMethodはこのメソッドを一度だけコールできますこのメソッドの前のすべてのコードを変数の初期化データ構造の投入などのために使用する必要がありますテスト実行のために必要なすべてを設定できますこのメソッドをコールした後適用される制限は最初の DML ステートメント (INSERTDELETEなど) または最初の Web サービス呼び出しに基づいています
startTestメソッドはテストのコンテキストを更新しませんコンテキストをテストに追加しますたとえばstartTestを呼び出す前に 98 件の SOQL クエリを作成しstartTest後の最初の有意な文が DML ステートメントである場合プログラムは追加の 100 件のクエリを作成できるようになりましたただしstopTestが呼び出されるとプログラムは元のコンテキストに戻り100 件の制限に達するまで追加できる SOQL クエリは2 件だけになります
stopTestメソッドはテストが終了する場合のテストコード内のポイントをマークしますこのメソッドはstartTestメソッドと組み合わせて使用しますそれぞれの testMethodはこのメソッドを一度だけコールできますこのメソッドをコールした後帰結表明が元のコンテキストで行われますstartTestメソッド後に作成されたすべての非同期コールはシステムによって収集されますstopTestを実行する場合すべての非同期プロセスが同期して実行されます
SOSL クエリのユニットテストへの追加テストメソッドが必ず予測されたとおりに動作するようにApex テストメソッドに追加される Salesforcecom オブジェクト検索言語 (SOSL) クエリはテストメソッドが実行された場合に検索結果の空のセットを返しますクエリが結果の空のリストを返さないようにする場合TestsetFixedSearchResultsシステムを使用して検索に返される一連のレコード ID を定義できますテストメソッドで後で実行される SOSL クエリはTestsetFixedSearchResultsメソッドで指定されたレコード ID のリストを返しますまたテストメソッドは TestsetFixedSearchResultsを複数回コールしてさまざまな SOSL クエリのさまざまな結果セットを定義できますテストメソッドで TestsetFixedSearchResultsメソッドをコールしない場合またはレコード ID のリストを指定しないでこのメソッドをコールする場合テストメソッドで後で実行される SOSL クエリは結果の空のリストを返します
TestsetFixedSearchResultsメソッドで指定されたレコード ID のリストはWHERE句または LIMIT句に指定されていない場合に通常 SOSL クエリで返された結果を置き換えますこれらの句が SOSL クエリにある場合固定された検索結果のリストに適用されます例
public class SoslFixedResultsTest1
public static testMethod void testSoslFixedResults() Id [] fixedSearchResults= new Id[1]fixedSearchResults[0] = 001x0000003G89h TestsetFixedSearchResults(fixedSearchResults)
Apex のテスト Version 180 | LimitsstartTestおよび stopTest の使用 | 126
ListltListltSObjectgtgt searchList = [FIND test IN ALL FIELDS RETURNING Account(id nameWHERE name = test LIMIT 1)]
ID が 001x0000003G89hである取引先レコードが FIND 句のクエリ文字列 (test) に一致しない場合レコードは SOSL ステートメントの RETURNING句に渡されますID 001x0000003G89hのレコードはWHERE句の条件に一致しレコードが返されますWHERE句に一致しない場合レコードは返されません
ユニットテストメソッドの実行
Salesforcecom のユーザインターフェースを使用してApex スクリプトのユニットテストを実行できます特定のクラスのユニットテストを実行することも組織内のすべてのユニットテストを実行することもできますユニットテストは引数をとらずデータをデータベースにコミットせず電子メールを送信せずメソッド定義でtestMethodキーワードを使用してフラグを立てます
特定のクラスのユニットテストを実行するには[設定] [開発] [Apex クラス] をクリックしクラス名をクリックして[テストを実行]をクリックします自分のクラスが別のクラスを呼び出した場合またはトリガが実行された場合Apex スクリプトが対象となるコードの割合計算に使用される合計量に含まれます
組織内のすべてのユニットテストを実行するには[設定] [開発] [Apex クラス] をクリックし[すべてのテストを実行] をクリックします
ユニットテストの実行結果ページには次のセクションがあります各セクションは展開したり折りたたんだりできます
bull テストランの回数失敗の回数ユニットテストが網羅する Apex スクリプトの割合を詳細に示す概要セクション
重要
- 少なくとも75の Apex スクリプトをユニットテストでカバーする必要がありますさらにすべてのトリガが一部のテスト範囲に含まれている必要があります
- 100 のスクリプトを可能な場合はユニットテストでカバーすることをお勧めします- Systemdebugへのコールはユニットテストの Apex コードの範囲の一部としてカウントされま
せん
bull テストの失敗回数 (発生した場合)bull コードカバー率セクション
このセクションでは組織のすべてのクラスおよびトリガおよびテストの対象となる各クラスおよびトリガのコードの行の割合を一覧表示しますカバー率の数値をクリックするとページが表示されテストの対象となるクラスまたはトリガのコードの行がすべて青でまたテストの対象外であるコードのすべての行が赤で強調表示されますまたクラスまたはトリガの特定の行がテストで実行された回数も表示されます
bull テストカバー率の警告 (発生した場合)bull デバッグログ
デバッグログは自動的に特定のログレベルとカテゴリに設定されます変更はできません
レベルCategory
INFOデータベース
Apex のテスト Version 180 | ユニットテストメソッドの実行 | 127
レベルCategory
FINEApex コードINFOApex プロファイリングINFOワークフローINFOValidation
またForcecom IDE でテストを実行することができます(httpswikiapexdevnetcomindexphpApex_Toolkit_for_Eclipse を参照)
Forcecom Web サービス API から runTests()コールを使用することもできます
RunTestsResult[] runTests(RunTestsRequest ri)
このコールを使用してRunTestsRequest オブジェクトで指定されているようにすべてのクラスのすべてのテスト特定の名前空間のすべてのテスト特定の名前空間のクラスのサブセットにあるすべてのテストを実行することができます次のものが返されます
bull 実行するテストの合計数bull コード範囲の統計 (下記参照)bull 失敗したテストそれぞれの情報bull 成功した各テストの情報bull テストの実行に要した時間
runTests()の詳細はhttpsyour_salesforce_serverserviceswsdlapexにある WSDL を参照してください your_salesforce_serverはna1salesforcecomなど組織があるサーバを示します
Salesforcecom 運用組織の管理者は Salesforcecom ユーザーインターフェースを使用して Apex スクリプトを変更できませんがrunTests()を使用して既存の項目に一意の制約を追加するなど既存のユニットテストが変更が行われた後に完了まで実行されていることを確認することが重要ですSalesforcecom 運用組織ではcompileAndTest API コールを使用して Apex スクリプトを変更する必要があります詳細は「Apex のディプロイ」 (ページ 382)を参照してください
runTests()の詳細は「Web サービス API コールおよび Apex の SOAP ヘッダ」 (ページ 406)を参照してください
ベストプラクティスのテスト
優れたテストは次のようになります
bull 可能な限り多くのコードの行をカバーします
重要
- 少なくとも75の Apex スクリプトをユニットテストでカバーする必要がありますさらにすべてのトリガが一部のテスト範囲に含まれている必要があります
- 100 のスクリプトを可能な場合はユニットテストでカバーすることをお勧めします
Apex のテスト Version 180 | ベストプラクティスのテスト | 128
- Systemdebugへのコールはユニットテストの Apex コードの範囲の一部としてカウントされません
bull 条件ロジックの場合 (3 項演算子など)コードロジックの各ブランチを実行しますbull 有効な入力および無効な入力を使用してメソッドへのコールを行いますbull エラーが予期されずtryhellipcatchブロックで取得されない限り例外を投げずに正常に完了しますbull 例外を取得するのではなく取得されたすべての例外を必ず処理しますbull Systemassertメソッドを使用してコードが適切に動作することを明らかにしますbull runAsメソッドを使用してさまざまなユーザーコンテキストでアプリケーションをテストしますbull isTestアノテーションを使用しますisTestで指定したクラスは1 MB という Apex スクリプトの組織内
の上限には含まれませんbull 一括トリガ機能を実行しますテスト内で最低 20 件のレコードを使用しますbull ORDER BYキーワードを使用しレコードが予期された順序で返されるようにしますbull レコード ID が順番に並んでいることを想定しません
複数のレコードを同じ要求で挿入しない限りレコード ID は昇順で作成されませんたとえば取引先 Aを作成しID 001D000000IEEmTを受信し取引先 B を作成すると取引先 B の ID は順序が上位になる場合とならない場合があります
bull Apex テスト結果ページにはコードカバー率のセクションがありますこのセクションでは組織のすべてのクラスおよびトリガおよびテストの対象となる各クラスおよびとリガのコードの行の割合を一覧表示しますカバー率の数値をクリックするとページが表示されテストの対象となるクラスまたはトリガのコードの行がすべて青でまたテストの対象外であるコードのすべての行が赤で強調表示されますまたクラスまたはトリガの特定の行がテストで実行された回数も表示されます
bull テストデータを次のように設定します
- テストクラスで必要なデータを作成しますテストは特定の組織のデータに依存する必要がありません- starttestメソッドをコールする前にすべてのテストデータを作成します- テストがコミットしていないためデータを削除する必要はありません
bull テストされるものだけでなくテスターがデータについて作成した推定予測される結果などについて言及するコメントを作成します
bull アプリケーションで個別にクラスをテストします1 回のテストでアプリケーション全体をテストしません
多くのテストを実行する場合次について考慮してください
bull Forcecom IDE ではApex プロジェクトの Read timeout値を増加する必要があります詳細はhttpswikiapexdevnetcomindexphpApex_Toolkit_for_Eclipse を参照してください
bull Salesforcecom ユーザーインターフェースで[すべてのテストを実行] ボタンを使用してすべてのテストを同時に実行する代わりに組織内のクラスを個別にテストする必要があります
テストの例
次の例では下記の種類のテストのケースについて示しています
bull 単一レコードおよび複数のレコードを含む正のケース (ページ 131)bull 単一レコードおよび複数のレコードを含む負のケース (ページ 132)
Apex のテスト Version 180 | テストの例 | 129
bull その他のユーザによるテスト (ページ 132)
テストは1 つのマイル追跡アプリケーションで使用されますアプリケーションの既存のコードは500 未満のマイルが 1 日に入力されることを確認しますプライマリオブジェクトは Mileage__c というカスタムオブジェクトですここに全体のテストクラスを示します次のセクションはコードの特定の部分を行います
isTest private class MileageTrackerTestSuite
static testMethod void runPositiveTestCases()
Double totalMiles = 0 final Double maxtotalMiles = 500 final Double singletotalMiles =300 final Double u2Miles = 100
Setup User User u1 = [select id from User where alias=auser]
Run As U1 SystemRunAs(u1)
Systemdebug(Inserting 300 miles(single record validation))
Mileage__c testMiles1 = new Mileage__c(Miles__c = 300 Date__c = Systemtoday()) inserttestMiles1
validate single insert for(Mileage__c m[SELECT miles__c FROM Mileage__c WHERE createdDate= TODAY and createdById = u1id and miles__c = null]) totalMiles += mmiles__c
SystemassertEquals(singletotalMiles totalMiles)
validate bulk totalMiles = 0 Systemdebug(Inserting 200 mileage records(bulkvalidation))
ListltMileage__cgt testMiles2 = new ListltMileage__cgt() for(integer i=0 ilt200 i++) testMiles2add( new Mileage__c(Miles__c = 1 Date__c = Systemtoday()) )
insert testMiles2
for(Mileage__c m[SELECT miles__c FROM Mileage__c WHERE createdDate = TODAY and createdById= u1id and miles__c = null]) totalMiles += mmiles__c
SystemassertEquals(maxtotalMiles totalMiles)
end RunAs(u1)
validate additional user totalMiles = 0 setup RunAs User u2 = [select id from Userwhere alias=tuser] SystemRunAs(u2)
Mileage__c testMiles3 = new Mileage__c(Miles__c = 100 Date__c = Systemtoday()) inserttestMiles3
for(Mileage__c m[SELECT miles__c FROM Mileage__c WHERE createdDate = TODAY and createdById= u2id and miles__c = null]) totalMiles += mmiles__c validateSystemassertEquals(u2Miles totalMiles)
SystemRunAs(u2)
runPositiveTestCases()
static testMethod void runNegativeTestCases()
User u3 = [select id from User where alias=tuser] SystemRunAs(u3)
Apex のテスト Version 180 | テストの例 | 130
Systemdebug(Inserting a record with 501 miles(negative test case))
Mileage__c testMiles3 = new Mileage__c( Miles__c = 501 Date__c = Systemtoday() )
try insert testMiles3 catch (DmlException e) Assert Error Message Systemassert(egetMessage()contains(Insert failedFirst exception on + row 0 first errorFIELD_CUSTOM_VALIDATION_EXCEPTION + Mileage request exceeds daily limit(500)[Miles__c]) egetMessage() )
Assert field SystemassertEquals(Mileage__cMiles__c egetDmlFields(0)[0])
Assert Status Code SystemassertEquals(FIELD_CUSTOM_VALIDATION_EXCEPTION egetDmlStatusCode(0) ) catch RunAs(u3) runNegativeTestCases()
class MileageTrackerTestSuite
正のテストケース
次では上記のコード特に単一レコードおよび複数レコードの正のテストケースを行います
1 スクリプトの次のステップを示すデバッグログにテキストを追加します
Systemdebug(Inserting 300 more milessingle record validation)
2 Mileage__c オブジェクトを作成しデータベースに挿入します
Mileage__c testMiles1 = new Mileage__c(Miles__c = 300 Date__c = Systemtoday() ) inserttestMiles1
3 挿入されたレコードを返してコードを検証します
for(Mileage__c m[SELECT miles__c FROM Mileage__c WHERE createdDate = TODAY and createdById= createdbyId and miles__c = null]) totalMiles += mmiles__c
4 systemassertEqualsメソッドを使用して期待された結果が返されることを確認します
SystemassertEquals(singletotalMiles totalMiles)
5 次のテストに移る前に合計マイル数を 0 に戻します
totalMiles = 0
6 200 件のレコードの一括挿入を作成してコードを検証します
まずスクリプトの次のステップを示すデバッグログにテキストを追加します
Systemdebug(Inserting 200 Mileage recordsbulk validation)
7 次に 200 件の Mileage__c レコードを挿入します
ListltMileage__cgt testMiles2 = new ListltMileage__cgt() for(integer i=0 ilt200 i++)testMiles2add( new Mileage__c(Miles__c = 1 Date__c = Systemtoday()) ) inserttestMiles2
Apex のテスト Version 180 | テストの例 | 131
8 SystemassertEqualsを使用して期待された結果が返されることを確認します
for(Mileage__c m[SELECT miles__c FROM Mileage__c WHERE createdDate = TODAY and createdById= createdbyId and miles__c = null]) totalMiles += mmiles__c SystemassertEquals(maxtotalMiles totalMiles)
負のテストケース
次は上記のコード特に負のテストケースを行います
1 runNegativeTestCasesという静的テストメソッドを作成します
static testMethod void runNegativeTestCases()
2 スクリプトの次のステップを示すデバッグログにテキストを追加します
Systemdebug(Inserting 501 miles negative test case)
3 501 マイルの Mileage__c record レコードを作成します
Mileage__c testMiles3 = new Mileage__c( Miles__c = 501 Date__c = Systemtoday() )
4 insertステートメントをtrycatchブロック内に配置します検証の例外を取得して生成されたエラーメッセージを確認します
try insert testMiles3 catch (DmlException e)
5 Systemassertおよび SystemassertEqualsを使用してテストを実行します次のコードを以前作成した catchブロックに追加します
Assert Error Message Systemassert(egetMessage()contains(Insert failedFirst exception+ on row 0 first error FIELD_CUSTOM_VALIDATION_EXCEPTION + Mileage request exceedsdaily limit(500) [Miles__c]) egetMessage())
Assert Field SystemassertEquals(Mileage__cMiles__c egetDmlFields(0)[0])
Assert Status Code SystemassertEquals(FIELD_CUSTOM_VALIDATION_EXCEPTION egetDmlStatusCode(0))
セカンドユーザとしてのテスト
次は上記のコード特にセカンドユーザとして実行します
1 次のテストに移る前に合計マイル数を 0 に戻します
totalMiles = 0
2 次のユーザを設定します
User u2 = [select id from User where alias=tuser] SystemRunAs(u2)
Apex のテスト Version 180 | テストの例 | 132
3 スクリプトの次のステップを示すデバッグログにテキストを追加します
Systemdebug(Setting up testing - deleting any mileage records for +UserInfogetUserName() + from today)
4 次に 1 件の Mileage__c レコードを挿入します
Mileage__c testMiles3 = new Mileage__c(Miles__c = 100 Date__c = Systemtoday()) inserttestMiles3
5 挿入されたレコードを返してコードを検証します
for(Mileage__c m[SELECT miles__c FROM Mileage__c WHERE createdDate = TODAY and createdById= u2Id and miles__c = null]) totalMiles += mmiles__c
6 systemassertEqualsメソッドを使用して期待された結果が返されることを確認します
SystemassertEquals(u2Miles totalMiles)
Apex のテスト Version 180 | テストの例 | 133
第 7 章
ダイナミック Apex
ダイナミック Apexによって開発者は以下の能力を供給することによってより柔軟なアプリケーションの作成が可能になります
トピック
bull Apex 定義情報についてbull sObjectとフィールドの定義情報へのアクセス
定義情報 はS オブジェクトと項目プロパティに関する情報を提供しますたとえばS オブジェクトの定義情報であればS オブジェ
bull 動的 SOQLbull 動的 SOSLbull ダイナミック DML
クトの種別が作成や復元などの操作S オブジェクトの名前と表示ラベルS オブジェクトの項目や子オブジェクトなどをサポートするかどうかといった情報です項目の定義情報であればその項目がデフォルト値を持っているか合計数を示す項目か項目の種別は何かといった情報です
定義情報は個別のレコードではなく組織内のobjectsについての情報を提供します
bull ダイナミックSOQLクエリを書く ダイナミックSOSLクエリとダイナミックDML
ダイナミック SOQL および SOSL クエリによりSOQL または SOSLを実行時に文字列として実行できます一方ダイナミック DMLによりレコードを動的に作成しDML を使用してデータベースに挿入できますダイナミック SOQLSOSLおよび DML を使用してユーザ権限をカスタマイズできるだけでなくアプリケーションを組織に合わせて的確にカスタマイズすることもできますこの特性はForcecom AppExchange からインストールされたアプリケーションに便利です
Apex 定義情報について
ApexはsObjectとフィールド定義情報に関して以下の2つのデータ構造を提供します
bull トークン-軽量直列化可能なsObjectへの参照またはコンパイル時に検証されるフィールド可能の参照bull 定義結果-sObjectまたはフィールドに関するすべての定義プロパティを含むオブジェクト定義結果オブジェ
クトは直列化不可能でランタイムで有効です
トークンからその定義結果まで移動するのはまたその逆は簡単ですsObjectとトークンは両方ともトークン用の定義結果を返すメソッドgetDescribeを持っています定義結果においてはgetSObjectTypeとgetSObjectFieldメソッドはsObjectとフィールド用にそれぞれトークンを返します
トークンは軽量なのでそれを使うことによってより速くて効率のよいコードの作成が可能です例えばスクリプトで使用する必要のあるsObjectまたはフィールドのタイプを決定する際にはsObjectまたはフィールドのトークンバージョンを使用してくださいsObjectがContactオブジェクトかどうか決定するためには例えばフィールドがNameフィールドまたはカスタム計算されたフィールドかは等価演算子(==)を使ってトークンを比較することができます
以下のコードはsObjectとフィールドプロパティについての情報にアクセスするためのトークンと定義結果の使い方の一般例を示しています
Create a new account as the generic type sObject sObject s = new Account()
Verify that the generic sObject is an Account sObject Systemassert(sgetsObjectType()== AccountsObjectType)
Get the sObject describe result for the Account object SchemaDescribeSObjectResult r =AccountsObjectTypegetDescribe()
Get the field describe result for the Name field on the Account objectSchemaDescribeFieldResult f = SchemasObjectTypeAccountfieldsName
Verify that the field token is the token for the Name field on an Account objectSystemassert(fgetSObjectField() == AccountName)
Get the field describe result from the token f = fgetSObjectField()getDescribe()
以下のアルゴリズムはApexスクリプト内で定義情報を使って作業可能な方法を示しています
1 組織内のsObject用のトークンのリストとマップを作成します Accessing All sObjects (ページ 138)参照 2 アクセスが必要なObjectを決定します3 sObject用の定義結果を作成します4 必要に応じてsObject用のフィールドトークンのマップを作成します Accessing All Field Describe Results for an
sObject (ページ 138)参照 5 アクセスが必要なスクリプトのフィールドのための定義結果を作成します
定義情報権限を理解する
Apexは通常システムモードで実行されますパッケージに含まれるすべてのクラスとトリガすなわち元々組織にあるものは動的に調べることのできるsObject上に制限を持っていませんこれは元々のスクリプトでは現在のユーザ権限に関わらず組織用のすべてのsObjectのマップを作成可能です
ダイナミック Apex Version 180 | Apex 定義情報について | 135
認定された Apex パートナーによって作成されたマージされたパッケージ内に含まれるForcecom AppExchangeからインストールされるダイナミックApexスクリプトは管理されたパッケージの外の sObject に対して制限されたアクセス権はありませんパートナーは管理されたパッケージの一部として含まれない標準sObjectへのアクセスを許可するためにパッケージ内でAPI Access値を設定可能ですパートナーは標準オブジェクトへのアクセスが要求可能な一方でカスタムオブジェクトは管理されたパッケージの一部として含まれず決してパッケージされたダイナミック Apex スクリプトによって参照されたりアクセスされたりできません
詳細はSalesforcecom オンラインヘルプの「パッケージの API とダイナミック Apex アクセスについて」を参照してください
sObjectトークンを使う
AccountとMyCustomObject__cなどのSObjectはトークンと定義結果情報にアクセスする特殊静的メソッドとメンバー変数を持った静的クラスとして機能します定義結果へのアクセスを得るためにコンパイルタイムにおいてsObjectとフィールド名を明示的に参照する必要があります
sObjectのトークンにアクセスするには以下のメソッドの1つを使ってください
bull AccountなどのsObjectタイプ上のsObjectTypeメンバー変数にアクセスしてくださいbull sObject定義結果sObject変数リストまたはマップ上のgetSObjectTypeメソッドを呼び出してください
SchemaSObjectTypeはsObjectトークン用のデータタイプです
以下の例ではAccount sObject用のトークンが返されます
SchemasObjectType t = AccountsObjectType
以下の例でもAccount sObject用のトークンが返されます
Account A = new Account() SchemasObjectType T = AgetSObjectType()
この例はsObjectまたはsObjectのリストが特定のタイプかどうか決定するために使われます
public class sObjectTest Create a generic sObject variable s SObject s =Databasequery(select id from account limit 1)
Verify if that sObject variable is an Account token SystemassertEquals(sgetSObjectType()AccountsObjectType)
一般的な sObjects のリストを作成 ListltsObjectgt l = new Account[]
Verify if the list of sObjects contains Account tokensSystemassertEquals(lgetSObjectType() AccountsObjectType)
いくつかの標準sObjectはsObjectTypeと呼ばれるフィールドを持っています例えばAssignmentRuleQueueSObjectおよびRecordTypeこれらのタイプのsObjectはトークンの取得に常にgetSObjectTypeメソッドを使いますプロパティを使う場合例えばRecordTypesObjectTypeフィールドが返されます
sObject定義結果を使う
sObjectの定義結果にアクセスするには以下のメソッドの1つを使ってください
bull sObjectトークン上のgetDescribeメソッドを呼び出してくださいbull sObjectの名前と一緒にスキーマsObjectType静的変数を使います例えばSchemasObjectTypeLead
ダイナミック Apex Version 180 | Apex 定義情報について | 136
SchemaDescribeSObjectResultはsObjectトークン用のデータタイプです
以下の例ではsObjectトークン上でgetDescribeを使います
SchemaDescribeSObjectResult D = AccountsObjectTypegetDescribe()
以下の例ではスキーマsObjectType静的メンバー変数を使います
SchemaDescribeSObjectResult D = SchemaSObjectTypeAccount
sObject定義結果に利用可能なメソッドについての詳細はsObject Describe Result Methods (ページ 245)を参照してください
フィールドトークンを使う
項目のトークンにアクセスするには以下のメソッドの1つを使ってください
bull sObject静的タイプの静的メンバー変数名例えばAccountNameにアクセスしてくださいbull 項目定義結果上のgetSObjectFieldメソッドを呼び出します
項目トークンはデータタイプSchemaSObjectFieldを使います
以下の例では項目トークンはAccountオブジェクトのAccountNumber項目用に返されます
SchemaSObjectField F = AccountAccountNumber
以下の例では項目トークンは項目定義結果から返されます
Get the describe result for the Name field on the Account object SchemaDescribeFieldResultf = SchemasObjectTypeAccountfieldsName
Verify that the field token is the token for the Name field on an Account objectSystemassert(fgetSObjectField() == AccountName)
Get the describe result from the token f = fgetSObjectField()getDescribe()
項目定義結果を使う
項目の定義結果にアクセスするには以下のメソッドの1つを使ってください
bull 項目トークン上のgetDescribeメソッドを呼び出してくださいbull sObjectトークンのfieldsメンバー変数に項目メンバー変数 NameBillingCityなど を使ってアクセスし
てください
項目定義結果はデータタイプSchemaDescribeFieldResultを使います
以下の例ではgetDescribeメソッドを使っています
SchemaDescribeFieldResult F = AccountAccountNumbergetDescribe()
この例では以下のfieldsメンバー変数メソッドを使います
SchemaDescribeFieldResult F = SchemaSObjectTypeAccountfieldsName
ダイナミック Apex Version 180 | Apex 定義情報について | 137
上記の例ではシステムは最終メンバー変数 (Name)がコンパイルタイムにおいて指定のsObjectに有効だと認証する特別解析を使いますパーサーがfieldsメンバー変数を見つけると後ろに戻ってsObject (Account)名を見つけfieldsメンバー変数に続く項目名が正当だと認証しますfieldsメンバー変数はこの方式で使われた時のみ機能します
1つのApexスクリプト内にたった10のfieldsメンバー変数ステートメントしか持つことができません
メモ 項目メンバー変数名またはgetMapメソッドのいづれかを使わずにfieldsメンバー変数を使うべきではありませんgetMapについての詳細はAccessing All Field Describe Results for an sObject (ページ138)を参照してください
項目定義結果に利用可能なメソッドについての詳細は「項目定義結果メソッド (ページ 249)」を参照してください
すべてのObjectにアクセスする
スキーマgetGlobalDescribeメソッドを使ってsObjectトークン 値 に対するすべてのsObject名 キー 間の関係を表すマップを返してください例
MapltString SchemaSObjectTypegt gd = SchemagetGlobalDescribe()
マップには以下の特徴があります
bull 権限に基づいて動的すなわち現在組織に利用可能なsObject上でランタイムで生成されますbull sObject名はケースインセンシティブですbull キーは必要に応じて名前空間を使いますbull キーはsObjectがカスタムオブジェクトかどうかを反映します
例えばマップを生成するコードブロックが名前空間N1にありまたsObjectもN1にある場合マップ内のキーはMyObject__cとして表されますしかしながらコードブロックが名前空間N1にありsObjectは名前空間N2にある場合キーはN2__MyObject__cです
さらに標準sObjectは名前空間プレフィックスを持っていません
sObject用のすべての項目定義結果にアクセスする
項目定義結果のgetMapメソッドを使ってsObject用のすべての項目名 キー と項目トークン 値 の間の関係を表すマップを返してください
以下の例では名前で項目にアクセスするのに使用可能なマップを生成します
MapltString SchemaSObjectFieldgt M = SchemaSObjectTypeAccountfieldsgetMap()
メモ このマップの値タイプは項目定義結果ではありません定義結果を使用するととても多くのシステムリソースを使いますそれは適切な項目を探すのに利用可能なトークンのマップです項目を決定したらその定義結果を作成してください
マップには以下の特徴があります
bull 動的でそのsObjectの項目上でランタイムにおいて作成されますbull すべての項目名はケースインセンシティブですbull キーは必要に応じて名前空間を使います
ダイナミック Apex Version 180 | Apex 定義情報について | 138
bull キーは項目がカスタムオブジェクトかどうかを反映します
例えばマップを生成するコードブロックが名前空間N1にありまた項目もN1にある場合マップ内のキーはMyField__cとして表されますしかしながらコードブロックが名前空間N1にあり項目は名前空間N2にある場合キーはN2__MyField__cです
さらに標準項目は名前空間プレフィックスを持っていません
sObject に関連するすべてのカテゴリのアクセス
describeDataCategoryGroupsおよび describeDataCategoryGroupStructuresメソッドを使用して特定のオブジェクトに関連するカテゴリを返します
1 選択したオブジェクトに関連するすべてのカテゴリグループを返します (describeDataCategoryGroups (ページ240) を参照)
2 返されたマップから詳細に検索するカテゴリグループ名と sObject 名を取得します ( SchemaDescribeDataCategoryGroupResult (ページ 240) を参照)
3 カテゴリグループおよび関連するオブジェクトを指定しこのオブジェクトに使用できるカテゴリを取得します ( describeDataCategoryGroupStructures (ページ 241) を参照)
describeDataCategoryGroupStructuresメソッドは指定したカテゴリグループのオブジェクトに使用できるカテゴリを返しますデータカテゴリの詳細はSalesforcecomオンラインヘルプの「データカテゴリとは」を参照してください
次の例ではdescribeDataCategoryGroupSampleメソッドは記事オブジェクトおよび質問オブジェクトに関連するすべてのカテゴリグループを返しますdescribeDataCategoryGroupStructuresメソッドはリージョンカテゴリグループの記事および質問に使用できるすべてのカテゴリを返します記事および質問に関する詳細はSalesforcecom オンラインヘルプ「記事の管理」「Answers の概要」を参照してください
次の例を使用するには下記の手順を実行する必要があります
bull Salesforce Knowledge を有効化するbull Answers 機能を有効化するbull リージョンというデータカテゴリグループを作成するbull リージョンを Answers で使用するデータカテゴリグループとして割り当てるbull リージョンデータカテゴリグループが Salesforce Knowledge に割り当てられていることを確認する
データカテゴリグループの作成についての詳細はSalesforcecomオンラインヘルプの「カテゴリグループの作成と変更」を参照してくださいAnswers の詳細はSalesforcecomオンラインヘルプの「回答の概要」を参照してください
public class DescribeDataCategoryGroupSample private void describeDataCategoryGroupSample()try Creating the list of sobjects to use for the describe call ListltStringgt objType= new ListltStringgt()
objTypeadd(KnowledgeArticleVersion) objTypeadd(Question)
Describe Call ListltSchemaDescribeDataCategoryGroupResultgt describeCategoryResult =SchemadescribeDataCategoryGroups(objType)
Using the results and retrieving the information for(SchemaDescribeDataCategoryGroupResultsingleResult describeCategoryResult) Getting the name of the categorysingleResultgetName()
Getting the name of label singleResultgetLabel()
ダイナミック Apex Version 180 | Apex 定義情報について | 139
Getting description singleResultgetDescription()
Getting the sobject singleResultgetSobject() catch(Exception e)
public class DescribeDataCategoryGroupStructures private voidgetDescribeDataCategoryGroupStructureResults() try Making the call to thedescribeDataCategoryGroups ListltStringgt objType = new ListltStringgt()objTypeadd(KnowledgeArticleVersion) objTypeadd(Question)ListltSchemaDescribeDataCategoryGroupResultgt describeCategoryResult =SchemadescribeDataCategoryGroups(objType)
Creating a list of pair objects to use as a parameter for the describe callListltDataCategoryGroupSobjectTypePairgt pairs = new ListltDataCategoryGroupSobjectTypePairgt()
Looping throught the first describe result to create the list of pairs for the seconddescribe call for(SchemaDescribeDataCategoryGroupResult singleResult describeCategoryResult) DataCategoryGroupSobjectTypePair p = newDataCategoryGroupSobjectTypePair() psetSobject(singleResultgetSobject())psetDataCategoryGroupName(singleResultgetName()) pairsadd(p)
describeDataCategoryGroupStructures() ListltSchemaDescribeDataCategoryGroupStructureResultgtresults = SchemadescribeDataCategoryGroupStructures(pairs false)
Getting data from the result for(SchemaDescribeDataCategoryGroupStructureResultsingleResult results) Get name of the associated Sobject singleResultgetSobject()
Get the name of the data category group singleResultgetName()
Get the name of the label singleResultgetLabel()
Get the description of the data category group singleResultgetDescription()
Get the top level categories DataCategory [] toplevelCategories =singleResultgetTopCategories()
Recursively get all the categories ListltDataCategorygt allCategories =getAllCategories(toplevelCategories) for(DataCategory category allCategories) Getthe name of the category categorygetName()
Get the label of the category categorygetName()
Get the list of sub categories in the category DataCategory [] childCategories =categorygetChildCategories() catch (Exception e)
private DataCategory[] getAllCategories(DataCategory [] categories) if(categoriesisEmpty())return new DataCategory[] else DataCategory category = categories[0] DataCategory[]temp = new DataCategory[]category categoriesremove(0)categoriesaddAll(categorygetChildCategories()) tempaddAll(getAllCategories(categories))return temp
動的 SOQL
動的ク SOQLはApexスクリプトを使ってランタイムにおいて SOQL 文字列の作成を参照します動的 SOQLによってさらに柔軟なアプリケーションの作成が可能になりますたとえばエンドユーザの入力をベースにした検索の作成または幅広い項目名を使ったレコードの更新が可能です
ダイナミック Apex Version 180 | 動的 SOQL | 140
ランタイムにおける動的 SOQLクエリの作成には次の方法の1つでデータベースqueryメソッドを使ってください
bull クエリが1つのレコードを返す時1つのsObjectが返します
sObject S = Databasequery(string_limit_1)
bull クエリが複数のレコードを返す時sObjectsのリストを返します
ListltsObjectgt L = Databasequery(string)
通常の割り当てステートメントと forループにおいてなどインライン SOQL クエリが使用可能な場合はいつでもデータベースqueryメソッドは利用可能です動的 SOQL クエリの処理とほぼ同様に結果は処理されます
動的 SOQL 結果は具体的な sObject として指定可能ですAccount または MyCustomObject__c などまたは一般的な sObject データ型として指定できますランタイムにおいてシステムはクエリのタイプが変数の宣言タイプとマッチしているか認証しますクエリが正しい sObject タイプを返さない場合はランタイムエラーが発生しますこれは一般的な sObject から具体的な sObject をキャストする必要がないことを意味します
動的 SOQLクエリは静的クエリと同じガバナー制限を持っていますガバナー制限の詳細は「実行ガバナーと制限の理解」を参照してください
SOQL クエリ構文の詳細は『Forcecom Web Services API Developers Guide』のwwwsalesforcecomusdeveloperdocsapiindex_CSHhtmsforce_api_calls_soqlhtm を参照してください
SOQL インジェクション
SOQL インジェクションとはSOQL ステートメントをスクリプトに送ることによって意図していなかったユーザがアプリケーションにデータベースメソッドを実行することですこれはアプリケーションが動的 SOQLを構築するためのエンドユーザ入力に依存し入力を適切に処理しない場合はいつでもApexスクリプト内で発生可能です
SOQL注入を防ぐためにはescapeSingleQuotesメソッドを使ってくださいこのメソッドはエスケープキャラクター()を文字列内のユーザからパスされるすべてのシングルクォーテーションマークに追加しますメソッドはすべてのシングルクォーテーションマークがデータベースメソッドの代わりに文字列の囲みとして使われることを確実にします
動的 SOSL
動的 SOSLはApexスクリプトを使ってランタイムにおいてSOSL文字列の作成を参照します動的 SOSLによってさらに柔軟なアプリケーションの作成が可能になりますたとえばエンドユーザの入力をベースにした検索の作成または幅広い項目名を使ったレコードの更新が可能です
動的 SOSLクエリをランタイムにおいて作成するには検索queryメソッドを使ってください例
ListltList ltsObjectgtgt myQuery = searchquery(SOSL_search_string)
ダイナミック Apex Version 180 | 動的 SOSL | 141
以下の例ではシンプルSOSLクエリ文字列を実行しています
String searchquery=FINDEdgeIN ALL FIELDS RETURNING Account(idname)Contact LeadListltListltSObjectgtgtsearchList=searchquery(searchquery)
各リストが特定のsObjectタイプの検索結果を含む場合sObjectのリストに対する動的 SOSLステートメント評価結果リストは常に動的 SOSLクエリにて指定されたのと同じ順番で返されます上記の例よりAccountからの結果が最初次がContactでその次がLeadです
通常の割り当てステートメントとforループにおいてなどインラインSOSLクエリが使用可能な場合はいつでも検索queryメソッドは利用可能です静的SOSLクエリの処理とほぼ同様に結果は処理されます
SOSL クエリはApexクラスおよび特定ブロックでのみサポートされますトリガで SOSL を使用することはできません
動的 SOSLクエリは静的クエリと同じガバナー制限を持っていますガバナー制限の詳細は「実行ガバナーと制限の理解」を参照してください
SOSLクエリ構文の詳細はForcecom Web Services API Developers Guide内のwwwsalesforcecomusdeveloperdocsapiindex_CSHhtmsforce_api_calls_soslhtmを参照してください
SOSL インジェクション
SOSL インジェクションとはSOSL ステートメントをスクリプトに送ることによって意図していなかったユーザがアプリケーションにデータベースメソッドを実行することですこれはアプリケーションが動的 SOSLを構築するためのエンドユーザ入力に依存し入力を適切に処理しない場合はいつでもApexスクリプト内で発生可能です
SOSL注入を防ぐためにはescapeSingleQuotesメソッドを使ってくださいこのメソッドはエスケープキャラクター()を文字列内のユーザからパスされるすべてのシングルクォーテーションマークに追加しますメソッドはすべてのシングルクォーテーションマークがデータベースメソッドの代わりに文字列の囲みとして使われることを確実にします
ダイナミック DML
ランタイムにおける定義情報の問い合わせとSOQLクエリの構築に加えて動的にsObjectを作成しそれをDMLを使ってデータベースに挿入可能です
指定されたタイプの新規sObjectを作成するにはsObjectトークン上でnewSObjectメソッドを使ってくださいトークンには具体的なsObjectタイプ Accountなど を与える必要がある点に注意してください例
Get a new account Account A = new Account() Get the token for the accountSchemasObjectType tokenA = AgetSObjectType() The following produces an error becausethe token is a generic sObject not an Account Account B = tokenAnewSObject() Thefollowing works because the token is cast back into an Account Account B =(Account)tokenAnewSObject()
sObjectトークンtokenAはAccountのトークンですが別にアクセスされるのでsObjectと考えられますnewSObjectメソッドを使うには具体的なsObjectタイプAccountに入れられる必要がありますキャストの詳細についてはクラスとキャスト (ページ 110)を参照してください
ダイナミック Apex Version 180 | ダイナミック DML | 142
newSObjectを使ってIDの指定も可能です例
SObject s = Databasequery(Select Id from account limit 1)[0]getSObjectType()newSObject([SELECT Id FROM Account LIMIT 1][0]id)
項目値を設定する取得する
Stringとして表現されるAPI名または項目のトークンのいづれかを使っている項目の値を設定または取得するためにオブジェクト上のgetとputメソッドを使ってください以下の例では項目AccountNumberのAPI名が使用されます
SObject s = [SELECT accountNumber FROM account LIMIT 1] Object o = sget(AccountNumber)sput(AccountNumber abc)
以下の例では代わりにAccountNumber項目のトークンを使います
SchemaDescribeFieldResult f = SchemasObjectTypeAccountfieldsAccountNumber Sobject s= Databasequery(SELECT AccountNumber FROM Account LIMIT 1) sput(fgetsObjectField()12345)
ObjectスカラデータタイプはsObject上の項目値を設定または取得するために総称データタイプとして使用可能ですこれはanyType項目タイプと同等ですObjectデータタイプはsObjectの総称的タイプとして使用可能なsObjectデータタイプとは違う点に注意してください
メモ 項目に割り当てた文字列値が長すぎる場合API バージョン 150 以上を使用して保存 (コンパイル)した Apex クラスにはランタイムエラーが発生します
外部キーを設定する取得する
ApexはAPIと同じ方法で名前 または外部ID による外部キーの投入をサポートします外部キーのスカラID値を設定または取得するにはgetまたはputメソッドを使ってください
外部キーに関連付けられたrecordを設定または取得するにはgetSObjectおよびputSObjectメソッドを使ってくださいこれらのメソッドはObjectではなくsObjectデータタイプで使用されなければならないことに注意してください例
SObject c = Databasequery(SELECT Id FirstName AccountId AccountName FROM Contact LIMIT1) SObject a = cgetSObject(Account)
子sObjectで作業中に親sObject値用の外部IDを指定する必要はありません親sObjectにIDを与えた場合はDML操作によって無視されますApexは外部キーが常に投入されたIDとともに親オブジェクトを返す関係SOQLクエリを通じて投入されると仮定していますIDがない場合は子オブジェクトとともに使ってください
例えばカスタムオブジェクトC1が子カスタムオブジェクトC2にリンクする外部キーc2__cを持っているとしますC1オブジェクトを作成し 値c2__rに割り当てられた 「xxx」と名づけられたC2レコードに関連付けたいとします親から子への関係を通じて投入されるので「xxx」レコードのIDは不要です例
insert new C1__c(name = x c2__r = new C2(name = xxx))
c2__rのIDに値を割り当てた場合それは無視されますIDがない場合それをレコードではなくオブジェクト (c2__c)に割り当ててください
ダイナミック Apex Version 180 | ダイナミック DML | 143
ダイナミックApexを使用して外部キーにアクセスすることもできます次の例はダイナミックApexを使用して親子関係のサブクエリから値を取得する方法について示しています
String queryString = SELECT Id Name (SELECT FirstName LastName from Contacts LIMIT 1)from Account SObject[] queryParentObject = Databasequery(queryString)
for (SObject parentRecord queryParentObject) Object ParentFieldValue =parentRecordget(Name) Prevent a null relationship from being accessed SObject[]childRecordsFromParent = parentRecordgetSObjects(Contacts) if (childRecordsFromParent= null) for (SObject childRecord childRecordsFromParent) Object ChildFieldValue1 =childRecordget(FirstName) Object ChildFieldValue2 = childRecordget(LastName)Systemdebug(Account Name + ParentFieldValue + Contact Name + ChildFieldValue1 + + ChildFieldValue2)
ダイナミック Apex Version 180 | ダイナミック DML | 144
第 8 章
Apex の一括処理
開発者はApexの一括処理を使用しForcecomプラットフォームで長時間にわたり実行される複雑なプロセスを構築できますたとえば特定
トピック
bull Apex の一括処理の使用 の日付を越えたレコードを検索してアーカイブに追加する夜間に実行bull Apex による共有管理について されるアーカイブソリューションを構築できますまたは毎晩すべて
の取引先と商談を探索しカスタム条件に基づき必要に応じて再割り当てをするデータの整理処理を構築できます
Apex の一括処理はインターフェースとして公開され開発者によって実行される必要があります一括処理ジョブはApex を使用して実行時に起動できます
キュー内または有効な一括処理ジョブを 5 件作成できますSalesforcecomの [スケジュール済みジョブ] を表示してまたはプログラムでForcecomWeb サービス API を使用して AsyncapexJob オブジェクトを問い合わせて現在のカウントを評価できます
警告 一括ジョブをトリガから開始する場合は細心の注意を払ってくださいトリガは 5 件を超える一括ジョブを追加しないようにする必要があります具体的にはAPIの一括更新インポートウィザードユーザインターフェースを使用した一括レコードの変更および複数のレコードを一度に更新できるすべてのケースなどです
一括ジョブはApex スケジューラを使用して特定の時刻に実行されるようプログラム的にスケジュールしたりまたは Salesforcecom ユーザインターフェースを使用して [Apex をスケジュール] ページを使用してスケジュールすることもできます[Apex をスケジュール] の詳細はSalesforcecom オンラインヘルプの「Apex のスケジュール」を参照してください
Apex の一括インターフェースはApex による共有管理の再適用にも使用されます
一括ジョブの詳細は「Apexの一括処理の使用 (ページ 146)」を参照してください
Apex による共有管理についての詳細は「Apex による共有管理について (ページ 153)」を参照してください
Apex の一括処理の使用
Apexの一括処理を使用するにはSalesforcecom提供のインターフェースDatabaseBatchableを実装するApexクラスを記述しプログラムに基づいてクラスを開始する必要があります
Apex の一括ジョブの実行を監視または停止するには[設定] [監視] [Apex] [ジョブ] をクリックします詳細はSalesforcecom オンラインヘルプの「Apex ジョブキュー」を参照してください
DatabaseBatchableインターフェースの実装
DatabaseBatchableインターフェースには実装しなければならない 3 つのメソッドが含まれています
bull startメソッド
global (DatabaseQueryLocator | IterableltsObjectgt) start(DatabaseBatchableContext bc)
startメソッドはApexの一括処理ジョブの開始時に呼び出されます startメソッドはインターフェースメソッド executeに渡すレコードまたはオブジェクトを収集するために使用します このメソッドはDatabaseQueryLocator オブジェクトまたはジョブに渡されるレコードまたはオブジェクトを含む反復可能オブジェクトを返します
DatabaseQueryLocator オブジェクトは一括処理ジョブで使用するオブジェクトの範囲を作成する単純なクエリ (SELECT) を使用する場合に使用します QueryLocator オブジェクトを使用する場合SOQL クエリによって取得されるレコード合計数に対するガバナ制限は無視されます たとえばAccount オブジェクトのApex の一括処理ジョブは組織内のすべての取引先レコード (最大 5000 万件のレコード) の QueryLocator を返すことができますもう 1 つの例としては組織内のすべての取引先レコードの QueryLocator を返す Contactオブジェクトの共有再適用があります
反復可能オブジェクトは一括処理ジョブの複雑な範囲を作成する必要がある場合に使用します またリスト全体を反復する独自のカスタムプロセスを作成するために反復可能オブジェクトを使用することもできます
重要 反復可能オブジェクトを使用する場合SOQL クエリによって取得されるレコード合計数に対するガバナ制限はそのまま適用されます
bull executeメソッド
global void execute(DatabaseBatchableContext BC listltPgt)
executeメソッドはメソッドに渡されるレコードの各一括処理に対して呼び出されますデータのそれぞれの塊に必要な処理をすべて実行する場合にこのメソッドを使用します
このメソッドは次を取ります
- DatabaseBatchableContext オブジェクトへの参照- ListltsObjectgtなどの sObjects のリストまたはパラメータ化された型のリスト DatabaseQueryLocator
を使用する場合は返されたリストを使用する必要があります
Apex の一括処理 Version 180 | Apex の一括処理の使用 | 146
bull finishメソッド
global void finish(DatabaseBatchableContext BC)
finishメソッドはすべてのバッチが処理された後にコールされます確認の電子メールの送信や処理完了後の操作を実行するのにこのメソッドを使用します
Apexの一括処理ジョブの各実行は個別のトランザクションと見なされますたとえば1000 件のレコードを含む Apex の一括処理ジョブがDatabaseexecuteBatchから任意の scopeパラメータを指定せずに実行されるとこのジョブはそれぞれ 200 件のレコードを含む 5 つのトランザクションと見なされます Apex のガバナ制限は各トランザクションでリセットされます最初のトランザクションが成功し2 番目が失敗した場合最初のトランザクションで行われたデータベースの更新はロールバックされません
DatabaseBatchableContext の使用
DatabaseBatchableインターフェースのすべてのメソッドは DatabaseBatchableContext オブジェクトへの参照を必要とします このオブジェクトは一括ジョブの進行状況を追跡するために使用します
次に DatabaseBatchableContext オブジェクトを含むインスタンスメソッドを示します
説明戻り値引数名前
この一括ジョブに関連するAsyncApexJobオブジェクトの ID を文字列として返します このメソッ
IDgetJobId
ドは一括処理ジョブのレコードの進行状況を追跡するために使用します
次の例ではDatabaseBatchableContext を使用して一括処理ジョブに関連する AsyncApexJob を問い合わせます
global void finish(DatabaseBatchableContext BC) DatabaseBatchableContext の一括処理ジョブを示す AsyncApexJob の ID を取得します AsyncApexJob オブジェクトを問い合わせて現在のジョブの情報を取得します AsyncApexJob a = [Select Id Status NumberOfErrors JobItemsProcessedTotalJobItems CreatedByEmail from AsyncApexJob where Id = BCgetJobId()] ジョブの完了を通知する電子メールを Apex ジョブの登録者に送信します MessagingSingleEmailMessage mail = newMessagingSingleEmailMessage() String[] toAddresses = new String[] aCreatedByEmailmailsetToAddresses(toAddresses) mailsetSubject(Apex Sharing Recalculation + aStatus)mailsetPlainTextBody (The batch Apex job processed + aTotalJobItems + batches with+ aNumberOfErrors + failures) MessagingsendEmail(new MessagingSingleEmailMessage[] mail )
DatabaseQueryLocator を使用した範囲の定義
startメソッドは一括処理ジョブまたは反復ジョブで使用するレコードを含む DatabaseQueryLocator オブジェクトを返すことができます
次に DatabaseQueryLocator の使用例を示します
global class SearchAndReplace implements DatabaseBatchableltsObjectgt
global final String Query global final String Entity global final String Field globalfinal String Value
global SearchAndReplace(String q String e String f String v)
Apex の一括処理 Version 180 | Apex の一括処理の使用 | 147
Query=q Entity=e Field=fValue=v
global DatabaseQueryLocator start(DatabaseBatchableContext BC) returnDatabasegetQueryLocator(query)
global void execute(DatabaseBatchableContext BC ListltsObjectgt scope) for(sobject s scope) sput(FieldValue) update scope
global void finish(DatabaseBatchableContext BC)
Apex の一括処理の反復を使用した範囲の定義
startメソッドは一括処理ジョブまたは反復ジョブで使用するレコードを含む DatabaseQueryLocator オブジェクトを返すことができます 反復ジョブを使用して返された項目をより簡単に行うことができます
global class batchClass implements Databasebatchable global Iterablestart(DatabaseBatchableContext info) return new CustomAccountIterable() global voidexecute(DatabaseBatchableContext info ListltAccountgt scope) ListltAccountgt accsToUpdate =new ListltAccountgt() for(Account a scope) aname = true anumberOfEmployees = 70accsToUpdateadd(a) update accsToUpdate global void finish(DatabaseBatchableContextinfo)
DatabaseexecuteBatchメソッドの使用
DatabaseexecuteBatchメソッドを使用して一括処理ジョブをプログラムに基づいて開始できます
重要 DatabaseexecuteBatchを呼び出すとSalesforcecom ではスケジュールされた時間のキューにのみプロセスを追加します 実際の実行はサービスの使用可能状態に応じて遅れる場合があります
DatabaseexecuteBatchメソッドは次の2 つのパラメータを採用します
bull DatabaseBatchableを実装するクラスbull DatabaseexecuteBatchメソッドはオプションのパラメータ scopeを採用します このパラメータは
executeメソッドに渡す必要があるレコードの数を指定します この値は 0 より大きくする必要があります上限はありませんが非常に大きい値を使用すると他に制限される場合がありますこれは渡される各レコードに対し多数の処理がありガバナ制限に達する場合に使用します レコード数を制限することによってトランザクションあたりの処理が制限されます
DatabaseexecuteBatchメソッドはジョブの進捗状況の追跡に使用できる AsyncApexJob オブジェクトの IDを返します 例
ID batchprocessid = DatabaseexecuteBatch(reassign)
AsyncApexJob aaj = [SELECT Id Status JobItemsProcessed TotalJobItems NumberOfErrorsFROM AsyncApexJob WHERE ID = batchprocessid ]
AsyncApexJob オブジェクトについての詳細は『Forcecom Web Services API Developers Guide』のAsyncApexJobを参照してください
Apex の一括処理の例
次に DatabaseQueryLocator の使用例を示します
global class UpdateAccountFields implements DatabaseBatchableltsObjectgt global final StringQuery global final String Entity global final String Field global final String Value
Apex の一括処理 Version 180 | Apex の一括処理の使用 | 148
global UpdateAccountFields(String q String e String f String v) Query=q Entity=eField=fValue=v
global DatabaseQueryLocator start(DatabaseBatchableContext BC) returnDatabasegetQueryLocator(query)
global void execute(DatabaseBatchableContext BC ListltsObjectgt scope) for(Sobject s scope)sput(FieldValue) update scope
global void finish(DatabaseBatchableContext BC)
次のコードを使用して上記のクラスを呼び出すことができます
id batchinstanceid = databaseexecuteBatch(new UpdateAccountFields(qefv) 5)
次のクラスはApex の一括処理を使用して特定のユーザが所有するすべての取引先を異なるユーザに割り当てることができます
global class OwnerReassignment implements DatabaseBatchableltsObjectgt String query Stringemail Id toUserId Id fromUserId
global databasequerylocator start(DatabaseBatchableContext BC) returnDatabasegetQueryLocator(query)
global void execute(DatabaseBatchableContext BC ListltsObjectgt scope) ListltAccountgt accns= new ListltAccountgt()
for(sObject s scope)Account a = (Account)s if(aOwnerid==fromUserId)aOwnerid=toUserId accnsadd(a)
update accns
global void finish(DatabaseBatchableContext BC) MessagingSingleEmailMessage mail = newMessagingSingleEmailMessage()
mailsetToAddresses(new String[] email) mailsetReplyTo(batchacmecom)mailsetSenderDisplayName(Batch Processing) mailsetSubject(Batch Process Completed)mailsetPlainTextBody(Batch Process has completed)
MessagingsendEmail(new MessagingSingleEmailMessage[] mail )
次のコードを使用して前述の例の OwnerReassignment クラスを実行できます
OwnerReassignment reassign = new OwnerReassignment() reassignquery=SELECT Id NameOwnerid FROM Account WHERE ownerid= + uid + reassignemail=adminacmecomreassignfromUserId = u reassigntoUserId = u2 ID batchprocessid =DatabaseexecuteBatch(reassign)
Apex の一括処理のコールアウトの使用
Apex の一括処理でコールアウトを使用するにはこのクラス定義で DatabaseAllowsCalloutsを使用する必要があります 例
global class SearchAndReplace implements DatabaseBatchableltsObjectgt DatabaseAllowsCallouts
コールアウトにはHTTP 要求および webServiceキーワードで定義されたメソッドが含まれています
Apex の一括処理 Version 180 | Apex の一括処理の使用 | 149
Apex の一括処理の状況の使用
Apexの一括処理ジョブの各実行は個別のトランザクションと見なされますたとえば1000 件のレコードを含む Apex の一括処理ジョブが任意の scopeパラメータを指定せずに実行されるとこのジョブはそれぞれ200 件のレコードを含む 5 つのトランザクションと見なされます
クラス定義でDatabaseStatefulを指定するとこれらのトランザクションで状況を保持できます処理されているレコードをカウントまたは集計する場合に役立ちますたとえばジョブで商談レコードが処理されたとします executeでメソッドを定義し処理された商談数の合計を集計できます
DatabaseStatefulを指定しない場合インターフェースメソッドのすべてのメンバー変数が元の値に戻されます
次の例ではレコードが処理されるとカスタム項目 total__cを集計します
global class SummarizeAccountTotal implements DatabaseBatchableltsObjectgt DatabaseStateful
global final String Query global integer Summary
global SummarizeAccountTotal(String q)Query=q Summary = 0
global DatabaseQueryLocator start(DatabaseBatchableContext BC) returnDatabasegetQueryLocator(query)
global void execute(DatabaseBatchableContext BC ListltsObjectgt scope) for(sObject s scope)Summary = IntegervalueOf(sget(total__c))+Summary
global void finish(DatabaseBatchableContext BC)
また変数を指定してクラスの最初の状況にアクセスします この変数を使用してDatabaseBatchableメソッドのすべてのインスタンスと最初の状況を共有します 例
取引先の sObject のリストを使用してインターフェースを実装します initialState 変数は最終として宣言されます
global class MyBatchable implements DatabaseBatchableltsObjectgt private final StringinitialState String query
global MyBatchable(String intialState) thisinitialState = initialState
global DatabaseQueryLocator start(DatabaseBatchableContext BC) Access initialStatehere
return DatabasegetQueryLocator(query)
global void execute(DatabaseBatchableContext BC ListltsObjectgt batch) AccessinitialState here
global void finish(DatabaseBatchableContext BC) Access initialState here
initialStateはクラスの「最初の」状況ですこれを使用して一括処理ジョブの実行時にクラスのインスタンス間で情報を受け渡すことはできません たとえばexecuteで initialStateの値を変更した場合処理されたレコードの 2 番目の塊は新しい値にアクセスできません最初の値だけがアクセス可能です
Apex の一括処理 Version 180 | Apex の一括処理の使用 | 150
Apex の一括処理のテスト
DatabaseBatchableインターフェースを実装する Apex をテストするにはインターフェースにより実装された各メソッドを直接コールし一括処理ジョブのシミュレーションを実行しなければなりません
一括処理 Apex をテストする場合executeメソッドの 1 つの実行だけをテストできます executeBatchメソッドの scopeパラメータを使用してexecuteメソッドに渡されるレコード数を制限しガバナ制限に達しないようにすることができます
executeBatchメソッドは匿名プロセスを開始します 一括処理 Apex をテストする場合結果に対してテストする前に一括処理ジョブを終了する必要があります executeBatchメソッドの周囲でテストメソッドstartTestおよび stopTestを使用してテストを続行する前に終了するようにします startTestメソッド後に作成されたすべての非同期コールはシステムによって収集されます stopTestを実行する場合すべての非同期プロセスが同期して実行されます
メモ startTestブロックおよび stopTestブロックで呼び出された futureまたは executeBatchなどの非同期コールはキュー内ジョブ数の制限に対してカウントされません
下記の例は OwnerReassignment クラスをテストします
public static testMethod void testBatch() user u = [SELECT ID username FROM User WHEREusername=testuser1acmecom] user u2 = [SELECT ID username FROM User WHEREusername=testuser2acmecom] String u2id = u2id 200 件のテスト アカウントを作成 - 1 つの実行をシミュレーションします 重要 - Salesforcecom テスト フレームで可能なのは 1 つの実行のテストだけです
List ltAccountgt accns = new ListltAccountgt() for(integer i = 0 ilt200 i++) Account a =new Account(name=testAccount+i Ownerid = uID) accnsadd(a)
insert accns
TestStartTest() OwnerReassignment reassign = new OwnerReassignment()reassignquery=SELECT ID Name Ownerid FROM Account WHERE ownerid= + uid + LIMIT=200 reassignemail=adminacmecom reassignfromUserId = uId reassigntoUserId= u2Id ID batchprocessid = DatabaseexecuteBatch(reassign) TestStopTest()
SystemAssertEquals(databasecountquery(SELECT count() + FROM Account WHEREownerid=u2ID) 200)
Apex の一括処理のガバナ制限
Apex の一括処理について次のガバナ制限に注意してください
bull 最大 5 件のキュー内またはアクティブ一括処理ジョブを Apex で行うことができますVisualforce でも 5 件の一括処理ジョブを行うことができます
bull ユーザは 1 度に最大 5 個のクエリカーソルを開くことができます たとえば5 個のカーソルが開き新しいカーソルを同じユーザが開こうとする場合にクライアント アプリケーションがログインしている場合5個のカーソルのうち最も古いカーソルが解放されます
メモ 異なる Forcecom 機能のカーソル制限は個別に追跡されます たとえば5 個の Apex クエリーカーソル5 個のバッチカーソル5 個の Visualforce 個を同時に開くことができます
bull DatabaseQueryLocatorオブジェクトでは最大 5000 万件のレコードが返されます 5000 万件以上のレコードが返された場合一括処理ジョブは即座に終了し「失敗」とマークされます
Apex の一括処理 Version 180 | Apex の一括処理の使用 | 151
bull オプションの scopeパラメータでサイズが指定されていない場合Salesforcecom はQueryLocator が 200 件のバッチに返したレコードを一括処理し各バッチを executeメソッドに渡します Apex ガバナ制限はexecuteの各実行でリセットされます
bull 組織で 24 時間当たり最大 250000 件の executeメソッドを呼び出すことができますbull startexecuteおよび finishメソッドはメソッドごとに 1 回のコールアウトだけ実行できます
Apex の一括処理のベストプラクティス
bull 一括ジョブをトリガから開始する場合は細心の注意を払ってください トリガは 5 件を超える一括ジョブを追加しないようにする必要があります 具体的にはAPI の一括更新インポートウィザードユーザインターフェースを使用した一括レコードの変更および複数のレコードを一度に更新できるすべてのケースなどです
bull DatabaseexecuteBatchを呼び出すとSalesforcecom ではスケジュールされた時間のキューにのみジョブを配置します 実際の実行はサービスの使用可能状態に応じて遅れる場合があります
bull 一括処理 Apex をテストする場合executeメソッドの 1 つの実行だけをテストできます executeBatch
メソッドの scopeパラメータを使用してexecuteメソッドに渡されるレコード数を制限しガバナ制限に達しないようにすることができます
bull executeBatchメソッドは匿名プロセスを開始します一括処理Apexをテストする場合結果に対してテストする前に一括処理ジョブを終了する必要があります executeBatchメソッドの周囲でテストメソッドstartTestおよび stopTestを使用してテストを続行する前に終了するようにします
bull ジョブトランザクション全体で変数またはデータを共有する場合はクラス定義で DatabaseStatefulを使用します これを使用しない場合各トランザクションの開始時にすべてのインスタンス変数が初期状態にリセットされます
bull futureとして宣言されたメソッドはDatabaseBatchableインターフェースを実装したクラスでは許可されません
bull futureとして宣言されたメソッドはApex の一括処理クラスからは呼び出せませんbull Apex の一括処理メソッドから DatabaseexecuteBatchメソッドを呼び出すことはできませんbull サービスの機能停止などの重大な障害が発生した場合進行中の処理は「失敗」とマークされます エラー
を修正するために一括処理ジョブをもう一度実行する必要がありますbull Apex の一括処理ジョブが実行されると一括処理ジョブを送信したユーザーに電子メール通知が送信されま
すまたは管理パッケージにコードが含まれ登録組織が一括処理ジョブを実行している場合[Apex例外通知受信者] 項目に表示された受信者に電子メールが送信されます
bull 各メソッドの実行では標準のガバナ制限非同期ブロックである Visualforce コントローラまたはWSDL メソッドが使用されます
bull Apex の一括処理が呼び出されるたびに AsyncApexJob レコードが作成されますこのレコードの ID を使用してジョブの状況エラーの数進行状況申請者を取得する SOQL クエリを構成します AsyncApexJob オブジェクトについての詳細は『Forcecom Web Services API Developers Guide』のAsyncApexJobを参照してください
bull クラス内のすべてのメソッドは globalとして定義する必要があります
Apex の一括処理 Version 180 | Apex の一括処理の使用 | 152
bull 共有再適用の場合Salesforcecom では一括処理内のレコードに対する Apex による共有管理をすべてexecuteメソッドで削除してから再作成することをお勧めしますこれにより共有が正確で完全であることを保証します
関連リンク例外ステートメント共有の理解
Apex による共有管理について
共有とはレコードに対してアクションを実行する許可をユーザまたはユーザグループに付与する行為のことです共有アクセス権はSalesforcecom ユーザインターフェースおよび Forcecom を使用して付与することもApex を使用してプログラムで付与することもできます
この項ではApex を使用した共有の概要について説明します
bull 共有の理解 (ページ 153)bull Apex を使用したレコードの共有 (ページ 156)bull Apex による共有管理の再適用 (ページ 160)
共有に関する詳細はSalesforcecom オンラインヘルプの「組織のデフォルト共有モデルの設定」 を参照してください
共有の理解共有 はカスタムオブジェクトとAccountContactOpportunityCase などの多くの標準オブジェクトのレコードレベルのアクセス制御を実現します管理者は最初にオブジェクトの組織の共有アクセスレベルを設定しレコード所有者ロール階層共有ルール共有の直接設定などに基づいてその他のアクセス権を付与します開発者は Apex 共有管理を使用できるようになりApex を使用したプログラムからのアクセス権の付与が可能になりますレコードに対するほとんどの共有は関連する共有オブジェクトで保持されますこれは他のプラットフォームのアクセス制御リスト (ACL) と似た機能です
共有タイプ
Salesforcecom には次の共有タイプがあります
Forcecom による共有管理Forcecom による共有管理ではレコードの所有者ロール階層および共有ルールに基づいて Forcecomによって付与される共有アクセス権を使用します
レコードの所有者各レコードはユーザ (場合によりカスタムオブジェクトケースおよびリードのキュー) が所有しますレコードの所有者にはフルアクセスが自動的に付与されレコードを参照編集移行共有および削除できます
Apex の一括処理 Version 180 | Apex による共有管理について | 153
ロール階層ロール階層によりその階層内の別のユーザよりも上位のユーザが下位ユーザの所有レコードまたは下位ユーザに共有されておりレコードに対して同じレベルのアクセス権を持つことができますそのためロール階層内のレコード所有者より上位のユーザにもそのレコードに対するフルアクセスが暗黙的に付与されますただしカスタムオブジェクトでは設定によりこの動作が無効になる場合がありますロール階層は共有レコードとして維持されるのではなくロール階層アクセス権が実行時に取得されます詳細はSalesforcecom オンラインヘルプの「階層を使用したアクセス権の制御」を参照してください
共有ルール共有ルールはシステム管理者が特定のユーザグループが所有するレコードへのアクセス権を特定のグループまたはロール内のユーザに自動的に付与する場合に使用します共有ルールはForcecomAppExchange からインストールしたアプリケーションのパッケージに追加したり共有ロジックをサポートする目的で使用したりすることはできません
Forcecomによる共有管理によって追加されたすべての暗黙的共有をSalesforcecomユーザインターフェースForcecom Web サービス APIまたは Apex を使用して直接変更することはできません
ユーザによる共有管理 (共有の直接設定)
ユーザによる共有管理によりレコードの所有者やレコードに対するフルアクセスを持つユーザはユーザまたはユーザグループとレコードを共有できます一般にこの処理はエンドユーザが単一レコードに対して実行しますレコードの所有者とロール階層内でその所有者の上位にあるユーザにのみレコードに対するフルアクセスが付与されます他のユーザにフルアクセスを付与することはできません特定のオブジェクトに対するオブジェクトレベルの「すべての編集」権限を持つユーザはレコードを手動で共有することもできますレコードの所有者が変わったり共有で付与されたアクセス権がオブジェクトの組織の共有デフォルトアクセスレベルより低くなった場合にユーザによる共有管理が削除されます
Apex による共有管理Apex による共有管理により開発者はアプリケーションの特定の共有要件を Apex を使用したプログラムでサポートできるようになりますこの共有タイプはForcecom による共有管理と似ていますがアプリケーション開発者のみが Apex を使用してこの共有を管理します「すべてのデータの編集」権限を持つユーザのみがレコードへの Apex による共有管理を追加または変更できますApex による共有管理はレコード所有者が変更しても維持されます
メモ Apex による共有管理はカスタムオブジェクトでのみ有効です
共有の理由項目
Salesforcecomユーザインターフェースにおけるカスタムオブジェクトの Reason項目はレコードで使用される共有の型を指定しますこの項目はApex または Forcecom API では rowCauseとなります
次のリスト項目のそれぞれはレコードに使用される共有の種類です[理由]項目値の下のテーブルおよび関連する rowCause値です
bull Forcecom による共有管理
Apex の一括処理 Version 180 | 共有の理解 | 154
rowCause値 (Apex または Forcecom API で使用)Reason Field値
ImplicitChild取引先の共有ImplicitParent関連するレコードの所有者または共有
所有者所有者
Team営業チームRule共有ルールTerritoryRuleテリトリー割り当てルール
bull ユーザによる共有管理
rowCause値 (Apex または Forcecom API で使用)Reason Field値
Manual共有の直接設定TerritoryManualテリトリー直接設定
bull Apex による共有管理
rowCause値 (Apex または Forcecom API で使用)Reason Field値
開発者による定義開発者による定義
Apex による共有管理の表示理由は開発者が定義します
アクセスレベル
レコードへのユーザのアクセス権を決定する際アクセスの最も権限の高いレベルを使用しますほとんどの共有オブジェクトは次のアクセス権をサポートしています
説明API 名アクセスレベル
レコードの所有者とロール階層内でその所有者の上位にあるユーザにのみレコードを参照または編集できますこのアクセスレベルは AccountShare オブジェクトにのみ適用されます
None非公開
指定されたユーザまたはグループがレコードを参照のみを実行できます
Read参照のみ
指定されたユーザまたはグループがレコードを参照および編集できます
Edit参照更新
Apex の一括処理 Version 180 | 共有の理解 | 155
説明API 名アクセスレベル
指定されたユーザまたはグループがレコードを参照編集移行共有削除できます
Allフルアクセス
メモ このアクセスレベルはForcecom 共有管理でのみ付与できます
Apex を使用したレコードの共有プログラムから共有にアクセスするには共有したい標準オブジェクトまたはカスタムオブジェクトに関連付けられている共有オブジェクトを使用する必要がありますたとえばAccountShare は Account オブジェクトの共有オブジェクトContactShare は Contact オブジェクトの共有オブジェクトとなります他のオブジェクトについても同様ですさらにすべてのカスタムオブジェクトの共有オブジェクトには次のように名前が付けられていますMyCustomObjectはカスタムオブジェクトの名前ですMyCustomObject__Share
主従関係の従側にあるオブジェクトには関連付けられた共有オブジェクトはありません従レコードへのアクセスは主の共有オブジェクトと関係の共有設定により定義されます詳細はSalesforcecomオンラインヘルプの「カスタム オブジェクトのセキュリティ」を参照してください
共有オブジェクトにはForcecom 共有管理ユーザ共有管理Apex 共有管理の 3 種類の共有すべてをサポートするレコードが含まれています組織のデフォルトロール階層「すべてのデータの表示」や「すべてのデータの編集」などのプロファイル権限により暗黙的にユーザに付与された共有はこのオブジェクトでは追跡されません
各共有オブジェクトには次のプロパティがあります
説明プロパティ名
共有 sObject に対し指定されたユーザまたはグループが権限を与えられたアクセスレベルプロパティ名はオブジェクト名に AccessLevelが追加されたものと
objectNameAccessLevel
なりますたとえばLeadShare オブジェクトのプロパティ名はLeadShareAccessLevelとなります有効な値は次のとおりですbull Edit
bull Read
bull All
メモ AllアクセスレベルはForcecom 共有管理でのみ使用できます
この項目にはその親オブジェクトに割り当てられた組織のデフォルトアクセスレベルよりも高いアクセスレベルが割り当てられていなければなりません詳細は「アクセスレベル」 (ページ 155)を参照してください
オブジェクトの IDこの項目は更新できませんParentID
Apex の一括処理 Version 180 | Apex を使用したレコードの共有 | 156
説明プロパティ名
ユーザまたはグループにアクセス権が付与される理由この理由によって共有のタイプが決まります共有のタイプは共有レコードの変更権限を制御しますこの項目は更新できません
RowCause
アクセス権を付与するユーザまたはグループの IDグループにはパブリックグループロールテリトリーを指定できますこの項目は更新できません
UserOrGroupId
詳細は『Forcecom Web Services API』の個別の共有オブジェクトを参照してください
Apex を使用したユーザ共有管理の作成
Apex を使用しユーザまたはグループに対してレコードの共有を直接設定することができますレコード所有者が変更になると共有は自動的に削除されます次にクラスの例を示します
public class JobSharing
static boolean manualShareRead(Id recordId Id userOrGroupId) カスタムオブジェクト Job の新しい共有オブジェクトを作成Job__Share jobShr = new Job__Share()
共有されるレコードの ID を設定jobShrParentId = recordId
アクセス権を付与するユーザまたはグループの ID を設定jobShrUserOrGroupId = userOrGroupId
アクセスレベルを設定jobShrAccessLevel = Read
共有の直接設定の場合rowCause を「manual」に設定 オブジェクト共有のデフォルト値が「manual」であるためこの行は省略できますjobShrRowCause = SchemaJob__ShareRowCauseManual
共有するレコードを挿入しsave result を取得 false パラメータは処理するレコードを複数渡された場合 部分処理を許可しますDatabaseSaveResult sr = Databaseinsert(jobShrfalse)
save result を処理if(srisSuccess()) 成功を表しますreturn true else 最初のsave result エラーを取得DatabaseError err = srgetErrors()[0]
エラーが 3 つのアクセスレベルに関連しているかどうかを確認 オブジェクトのデフォルト値と同等かより権限の大きいアクセスレベルは 許可されません これらの共有レコードは不要であるため挿入例外が許可されますif(errgetStatusCode() == StatusCodeFIELD_INTEGRITY_EXCEPTION ampamperrgetMessage()contains(AccessLevel)) 成功を表しますreturn true else 失敗を表しますreturn false
manualShareRead メソッドのテストstatic testMethod void testManualShareRead() テストのためのユーザを選択ListltUsergt users = [select id from user where isActive = true limit 2] Iduser1Id = users[0]Id Id user2Id = users[1]Id
新規ジョブの作成Job__c j = new Job__c() jName = Test Job jOwnerId = user1Id insertj
レコード所有者ではないユーザに共有の直接設定を挿入SystemassertEquals(manualShareRead(jIduser2Id) true)
ジョブ共有レコードのクエリを実行ListltJob__Sharegt jShrs = [select id userOrGroupIdaccessLevel rowCause from job__share where parentId = jId and userOrGroupId= user2Id]
ジョブに対する 1 つの共有の直接設定をテストSystemassertEquals(jShrssize() 1 Set the
Apex の一括処理 Version 180 | Apex を使用したレコードの共有 | 157
objects sharing model to Private)
共有の直接設定の属性をテストSystemassertEquals(jShrs[0]accessLevel Read)SystemassertEquals(jShrs[0]rowCause Manual) SystemassertEquals(jShrs[0]userOrGroupIduser2Id)
不正なジョブ ID をテストdelete j
削除されたジョブ ID に対する共有の直接設定を挿入SystemassertEquals(manualShareRead(jIduser2Id) false)
重要 組織のデフォルトアクセスレベルは最も権限の大きいアクセスレベルに設定することはできませんカスタムオブジェクトの場合は Public ReadWrite となります詳細は「アクセスレベル」 (ページ155)を参照してください
Apex による共有管理の作成
Apex による共有管理を使用し開発者はアプリケーションの動作をサポートする共有をプログラムで操作できるようになりますこの共有タイプはForcecom による共有管理と似ていますがアプリケーション開発者のみが Apex を使用してこの共有を管理します「すべてのデータの編集」権限を持つユーザのみがレコードへの Apex による共有管理を追加または変更できますApex による共有管理はレコード所有者が変更しても維持されます
メモ Apex による共有管理はカスタムオブジェクトでのみ有効です
Apex による共有管理にはApex 共有の理由を使用する必要がありますApex 共有の理由は開発者がユーザやユーザグループに対してレコードを共有した理由を追跡するための 1 つの方法です複数の Apex 共有理由を使用することで共有レコードの更新や削除に必要なコーディングを簡略化することができますまた開発者は別の理由を使用して同じユーザやグループに何度も共有することができるようになります
Apex 共有の理由はオブジェクトの詳細ページとして定義されますApex 共有の理由にはそれぞれラベルと名前が付けられます
bull ユーザインターフェースでレコードの共有を参照すると[理由]列に表示ラベルが表示されますこれによりユーザとシステム管理者が共有の目的を理解できます表示ラベルはトランスレーションワークベンチ使用した翻訳でも有効化されます
bull この名前はAPI および Apex で理由を参照するときに使用します
Apex 共有の理由名の形式は次のとおりです
MyReasonName__c
Apex 共有の理由は次のようにプログラムから参照できます
SchemaCustomObject__SharerowCauseSharingReason__c
たとえばJob というオブジェクトの Apex 共有の理由である Recruiter は次のように参照できます
SchemaJob__SharerowCauseRequester__c
Apex の一括処理 Version 180 | Apex を使用したレコードの共有 | 158
詳細は「スキーマメソッド」 (ページ 238)を参照してください
Apex 共有の理由を作成する手順は次のとおりです
1 [設定] [作成] [オブジェクト] をクリックします2 カスタムオブジェクトを選択します3 [Apex 共有の理由] 関連リストで [新規] をクリックします4 Apex 共有の理由の表示ラベルを入力しますユーザインターフェースでレコードの共有を参照すると[理
由]列に表示ラベルが表示されます表示ラベルはトランスレーションワークベンチ使用した翻訳でも有効化されます
5 Apex 共有の理由の名前を入力しますこの名前はForcecom API および Apex で理由を参照するときに使用しますこの名前はアンダースコアと英数字のみを含み組織内で一意の名前にする必要があります最初は文字であることスペースは使用しない最後にアンダースコアを使用しない2 つ続けてアンダースコアを使用しないという制約があります
6 [保存] をクリックします
Apex による共有管理例
次の例では人事採用アプリケーションの構築中でJob というカスタムオブジェクトが存在すると仮定していますこのジョブにリストされた採用担当者および採用担当マネージャにレコード所有者とほぼ同様にレコードへのフルアクセス権を付与したいと考えています次のトリガはジョブ作成時に採用担当者および採用担当マネージャにアクセス権を付与します
trigger JobApexSharing on Job__c (after insert)
if(triggerisInsert) Job に共有オブジェクトの新しいリストを作成ListltJob__Sharegt jobShrs =new ListltJob__Sharegt()
採用担当者および採用担当マネージャの共有のための変数を宣言Job__Share recruiterShr Job__SharehmShr
for(Job__c job triggernew) 新規共有オブジェクトのインスタンス化recruiterShr = newJob__Share() hmShr = new Job__Share()
共有されるレコードの ID を設定recruiterShrParentId = jobId hmShrParentId = jobId
アクセス権を付与するユーザまたはグループの ID を設定recruiterShrUserOrGroupId =jobRecruiter__c hmShrUserOrGroupId = jobHiring_Manager__c
アクセスレベルを設定recruiterShrAccessLevel = edit hmShrAccessLevel = read
採用担当者と採用担当マネージャの Apex 共有の理由を設定recruiterShrRowCause =SchemaJob__ShareRowCauseRecruiter__c hmShrRowCause =SchemaJob__ShareRowCauseHiring_Manager__c
挿入するためにリストにオブジェクトを追加jobShrsadd(recruiterShr) jobShrsadd(hmShr)
共有レコードを挿入しsave result を取得 処理するレコードを複数渡された場合 部分処理を許可しますDatabaseSaveResult[] lsr = Databaseinsert(jobShrsfalse)
カウンタを作成Integer i=0
save results を処理for(DatabaseSaveResult sr lsr) if(srisSuccess()) 最初の saveresult エラーを取得error DatabaseError err = srgetErrors()[0]
エラーが 3 つのアクセスレベルに関連しているかどうかを確認 オブジェクトのデフォルト値と同等かより
Apex の一括処理 Version 180 | Apex を使用したレコードの共有 | 159
権限の大きいアクセスレベルは 許可されません これらの共有レコードは不要であるため 挿入例外が許可されますif((errgetStatusCode() == StatusCodeFIELD_INTEGRITY_EXCEPTION ampamperrgetMessage()contains(AccessLevel))) エラーが 3 つのアクセスレベルに関連していない場合エラーを発生triggernewMapget(jobShrs[i]ParentId) addError(Unable to grant sharing accessdue to following exception + errgetMessage()) i++
重要 組織のデフォルトアクセスレベルは最も権限の大きいアクセスレベルに設定することはできませんカスタムオブジェクトの場合は Public ReadWrite となります詳細は「アクセスレベル」 (ページ155)を参照してください
Apex による共有管理の再適用組織のデフォルトアクセスレベルが変更されるとSalesforcecomはオブジェクトの全レコードの共有を自動的に再適用します再適用により適切な場合は Forcecom 共有管理が追加されますまた付与されたアクセス権が冗長である場合はすべての共有タイプが削除されますたとえばオブジェクトの共有モデルが「非公開」から「公開参照のみ」に変更されるとユーザに「参照のみ」アクセス権を付与する共有の直接設定が削除されます
Apex 共有管理を再適用するにはSalesforcecom が提供する再適用を行うインターフェースを実装するApex クラスを記述する必要がありますその後Apex 共有管理の再適用リストのカスタムオブジェクトの詳細ページにおいてクラスとカスタムオブジェクトを関連付ける必要があります
メモ Apex 共有管理の再適用は現在限定リリースプログラムで使用できます組織での Apex 共有管理の再適用の詳細についてはsalesforcecom までお問い合わせください
その後Apex共有の理由を指定するカスタムオブジェクト詳細ページからこのクラスを実行しますアプリケーションのロジックに定義されたユーザへのアクセス権限の付与においてオブジェクトへのロックにより Apexスクリプトが実行されない場合管理者はそのオブジェクトの Apex 共有管理を再適用しなければならないことがありますDatabaseexecuteBatchメソッドをApex共有管理の再適用をプログラムに基づいて開始することもできます
メモ カスタムオブジェクトの組織のデフォルト共有アクセスレベルが更新される度にそのカスタムオブジェクトに関連付けられた Apex 最適用クラスもまた実行されます
Apexの再適用の実行を監視または停止するには[設定] [監視] [Apex] [ジョブ]をクリックします詳細はSalesforcecom オンラインヘルプの「Apex ジョブキュー」を参照してください
共有の再適用のための Apex クラスの作成
Apex 共有管理を再適用するには再適用を行う Apex クラスを記述する必要がありますこのクラスはSalesforcecom が提供する DatabaseBatchableインターフェースを実装している必要があります
DatabaseBatchableインターフェースはApex共有管理の再適用などすべてのApexの一括処理プロセスに使用されますこのインターフェースは組織で複数回実装できます実装しなければならないメソッドの詳細は「Apex の一括処理の使用 (ページ 146)」を参照してください
Apex 共有管理の再適用を作成する前にベストプラクティスについても検討してください
Apex の一括処理 Version 180 | Apex による共有管理の再適用 | 160
Apex による共有管理の再適用例
この例では人事採用アプリケーションの構築中でJob というオブジェクトが存在すると仮定していますジョブにリストされた採用担当者および採用担当マネージャにレコードへのアクセス権が付与されていることを確認したいと考えています次の Apex クラスがその確認を行います
global class JobSharingRecalc implements DatabaseBatchableltsObjectgt
start メソッドは共有の再適用の最初にコールされます このメソッドは再適用する必要のあるレコードを含む SOQL クエリロケータを返します このメソッドは global でなければなりませんglobalDatabaseQueryLocator start(DatabaseBatchableContext BC) returnDatabasegetQueryLocator([SELECT Id Hiring_Manager__c Recruiter__c FROM Job__c])
executeBatch メソッドはstart から返されたレコードのチャンクによって実行されます このメソッドはglobal でなければなりません global void execute(DatabaseBatchableContext ListltsObjectgtscope) メソッドに渡されたレコードの塊のマップを作成しますMapltID Job__cgt jobMap = new MapltIDJob__cgt((ListltJob__cgt)scope)
挿入する Job__Share オブジェクトのリストを作成ListltJob__Sharegt newJobShrs = newListltJob__Sharegt()
Job レコードのすべての既存の共有レコードをバッチから検索 このアプリケーションの Apex 共有の理由を使用しているレコードのみが返されますListltJob__Sharegt oldJobShrs = [select id from Job__Sharewhere Id In jobMapkeySet() and (rowCause = SchemaJob__SharerowCauseRecruiter__c orrowCause = SchemaJob__SharerowCauseHiring_Manager__c)]
各 Job レコードに対し採用担当者と採用担当マネージャの新しい共有レコードを 作成for(Job__c job jobMapvalues()) Job__Share jobHMShr = new Job__Share() Job__Share jobRecShr = newJob__Share()
Job のアクセス権を付与するユーザ (採用担当マネージャ) の ID を設定jobHMShrUserOrGroupId =jobHiring_Manager__c
ジョブの採用担当マネージャには常に「参照のみ」アクセス権が付与されていなければなりませんjobHMShrAccessLevel = Read
共有されるレコードの IDjobHMShrParentId = jobId
採用担当マネージャの Apex 共有の利用に rowCause を設定 これにより共有レコードを Apex 共有管理として確立しますjobHMShrRowCause = SchemaJob__ShareRowCauseHiring_Manager__c
挿入するために共有レコードをリストに追加newJobShrsadd(jobHMShr)
Job のアクセス権を付与するユーザ (採用担当者) の ID を設定jobRecShrUserOrGroupId =jobRecruiter__c
ジョブの採用担当マネージャには常に「参照更新」アクセス権が付与されていなければなりませんjobRecShrAccessLevel = Edit
共有されるレコードの IDjobRecShrParentId = jobId
採用担当者の Apex 共有の利用に rowCause を設定 これにより共有レコードを Apex 共有管理として確立しますjobRecShrRowCause = SchemaJob__ShareRowCauseRecruiter__c
挿入するために共有レコードをリストに追加newJobShrsadd(jobRecShr)
try 既存の共有レコードを削除 これにより新しい共有レコードを最初から記述できますDeleteoldJobShrs
新しい共有レコードを挿入しsave result を取得 false パラメータは処理するレコードを複数渡された
Apex の一括処理 Version 180 | Apex による共有管理の再適用 | 161
場合 部分処理を許可しますDatabaseSaveResult[] lsr = Databaseinsert(newJobShrsfalse)
save results を挿入のために処理for(DatabaseSaveResult sr lsr) if(srisSuccess()) 最初の save result エラーを取得DatabaseError err = srgetErrors()[0]
エラーが明白なアクセスレベルに関連しているかどうかを確認 オブジェクトのデフォルト値と同等かより権限の大きいアクセスレベルは 許可されません これらの共有レコードは不要であるため 挿入例外が許可されますif((errgetStatusCode() == StatusCodeFIELD_INTEGRITY_EXCEPTION ampamperrgetMessage()contains(AccessLevel))) エラーは明白なアクセスレベルとは無関係です Apexジョブの送信者に電子メールを送信MessagingSingleEmailMessage mail = newMessagingSingleEmailMessage() String[] toAddresses = new String[] adminyourcompanycommailsetToAddresses(toAddresses) mailsetSubject(Apex Sharing Recalculation Exception)mailsetPlainTextBody (The Apex sharing recalculation threw the following exception +errgetMessage()) MessagingsendEmail(new MessagingSingleEmailMessage[] mail ) catch(DmlException e) 処理が失敗した場合はApex ジョブの送信者に電子メールを送信MessagingSingleEmailMessage mail = new MessagingSingleEmailMessage() String[] toAddresses= new String[] adminyourcompanycom mailsetToAddresses(toAddresses)mailsetSubject(Apex Sharing Recalculation Exception) mailsetPlainTextBody (The Apexsharing recalculation threw the following exception + egetMessage())MessagingsendEmail(new MessagingSingleEmailMessage[] mail )
finish メソッドは共有の再適用の最後にコールされます このメソッドは global でなければなりませんglobal void finish(DatbaseBatchableContext BC) Apex ジョブの送信者にジョブが完了したこと
を通知する電子メールを送信MessagingSingleEmailMessage mail = new MessagingSingleEmailMessage()String[] toAddresses = new String[] adminyourcompanycommailsetToAddresses(toAddresses) mailsetSubject(Apex Sharing Recalculation Completed)mailsetPlainTextBody (The Apex sharing recalculation finished processing)MessagingsendEmail(new MessagingSingleEmailMessage[] mail )
Apex による共有管理の再適用のテスト
DatabaseBatchableインターフェースを実装する Apex をテストするにはインターフェースにより実装された各メソッドを個別にコールし共有の再適用のシミュレーションを実行しなければなりません
DatabaseBatchableインターフェースを実装するクラスがメソッドに渡されるDatabaseBatchInput引数で getAsyncApexJobIdメソッドを使用している場合テストメソッド setupAsyncApexJobを使用したテストで使用するために AsyncApexJob レコードを準備する必要があります詳細は「テストメソッド」 (ページ 293)を参照してください
startから返された QueryLocator オブジェクトをテストするにはDatabaseQueryLocator の getQueryメソッドを使用する必要があります詳細は「データベースのApexの一括処理オブジェクトとメソッド」 (ページ273)を参照してください
下記の例では前の項のクラスでテストを行いテストメソッド setupAsyncApexJobの使い方について説明しますまたstartから返された QueryLocator オブジェクトのテスト方法も示します
public class JobSharingTester
JobSharingRecalc クラスのテストstatic testMethod void testApexSharing() DatabaseBatchable インターフェースを実装するクラスをインスタンス化JobSharingRecalc recalc = newJobSharingRecalc()
AsyncApexJob オブジェクトの準備に必要な変数を宣言Integer totalItems Integer itemsProcessedInteger errs
テストで使用する新規 Job を作成 少なくとも 1 つの Job が存在していなければなりませんJob__c j= new Job__c() jName = Test Job jRecruiter__c = UserInfogetUserId()
Apex の一括処理 Version 180 | Apex による共有管理の再適用 | 162
jHiring_Manager__c = UserInfogetUserId() insert j
TeststartTest()
バッチ処理可能なクラスから start メソッドをコールDatabaseQueryLocator ql = recalcstart()
バッチ処理可能なクラスからの start メソッドのコールで 正しいクエリロケータが返されることをテストクエリの結果を文字列で表したものを取得するには QueryLocatorgetQuery メソッドを使用する 必要がありますSystemassertEquals(qlgetQuery() SELECT Id Hiring_Manager__c Recruiter__c fromJob__c)
バッチ処理可能なクラスから executeBatch メソッドをコールするための変数を設定 バッチ処理全体に含まれるチャンク数excution totalItems = 1 バッチ処理全体で処理されたチャンク数itemsProcessed =0 バッチ処理全体のエラー数チャンク 1 個あたりのエラーは 1 つerrs = 0
クエリロケータのチャンクの start メソッドから返される クエリのレコード 返されるレコードの最大数は 200 レコードMapltID Job__cgt jobMap = new MapltID JOB__cgt( [SELECT Id Hiring_Manager__cRecruiter__c FROM Job__c limit 200])
バッチ可能なクラスから execute メソッドをコールrecalcexecute(jobMapvalues())
クエリジョブは executeBatch メソッドの引数として渡されます クエリはexecute メソッドで挿入されたジョブと関連する共有レコードを 返しますListltJob__cgt jobs = [SELECT Id Hiring_Manager__cRecruiter__c (Select Id ParentId UserOrGroupId AccessLevel RowCause FROM Shares where(rowCause = SchemaJob__SharerowCauseRecruiter__c or rowCause =SchemaJob__SharerowCauseHiring_Manager__c)) from Job__c WHERE Id In jobMapkeySet()]
ジョブに Apex 共有管理が存在することを確認for(Job__c job jobs) 各ジョブには最大 2 つのApex 共有管理レコードが存在しますSystemassert(jobSharessize() lt= 2)
for(Job__Share jobShr jobShares) Job に対し採用担当マネージャの共有レコードをテストif(jobShrRowCause == SchemaJob__ShareRowCauseHiring_Manager__c)SystemassertEquals(jobShrUserOrGroupIdjobHiring_Manager__c)SystemassertEquals(jobShrAccessLevelRead) Job に対し採用担当者の共有レコードをテストelse if(jobShrRowCause == SchemaJob__ShareRowCauseRecruiter__c)SystemassertEquals(jobShrUserOrGroupIdjobRecruiter__c)SystemassertEquals(jobShrAccessLevelEdit)
バッチ処理可能なクラスから finish メソッドをコールするための変数を設定 バッチ処理全体に含まれるチャンク数excution totalItems = 1 バッチ処理全体で処理されたチャンク数itemsProcessed = 1 バッチ処理全体のエラー数チャンク 1 個あたりのエラーは 1 つerrs = 0
バッチ可能なクラスから finish メソッドをコールrecalcfinish()
TeststopTest()
再適用に使用される Apex クラスの関連付け
再適用に使用される Apex クラスはカスタムオブジェクトと関連付けられていなければなりません
Apex による共有管理の再適用クラスをカスタムオブジェクトと関連付ける手順は次のとおりです
1 [設定] [作成] [オブジェクト] をクリックします2 カスタムオブジェクトを選択します3 [Apex 共有の再適用] 関連リストで [新規] をクリックします
Apex の一括処理 Version 180 | Apex による共有管理の再適用 | 163
4 このオブジェクトの Apex 共有を再適用する Apex クラスを選択します選択するクラスはDatabaseBatchableインターフェースを実装している必要があります同じApexクラスを同じカスタムオブジェクトと複数関連付けることはできません
5 [保存] をクリックします
Apex の一括処理 Version 180 | Apex による共有管理の再適用 | 164
第 9 章
管理パッケージでの Apex の開発
パッケージとは個々のコンポーネントなどの小さいものや関連アプリケーションのセットなどの大きいものを格納するコンテナですパッ
トピック
bull パッケージバージョン ケージの作成後他のSalesforcecomユーザおよび組織 (社外のユーザbull Apex の廃止 組織も含む) にそのパッケージを配布できます組織は他の多くの組
織でダウンロードおよびインストールできる単一の管理パッケージを作bull パッケージバージョンの動作成できます管理パッケージは未管理パッケージとは異なりコンポーネントの一部がロックされていて後でアップグレードできます未管理パッケージにはロックされたコンポーネントは含まれておらずアップグレードはできません
ここでは管理パッケージの Apex の開発に関連する次のトピックについて説明します
bull パッケージバージョンbull Apex の廃止bull パッケージバージョンの動作
パッケージバージョン
パッケージでアップロードされる一連のコンポーネント示す番号ですバージョン番号の形式はmajorNumberminorNumberpatchNumber (例 213) となりますメジャー番号およびマイナー番号はメジャーリリースごとに選択された値に増えますpatchNumberはパッチリリース時のみ生成されますpatchNumber
がない場合0 であるものとしますパッチバージョンは現在パイロットプログラムで使用できます組織のパッチバージョンの有効化に関する詳細はsalesforcecomまでお問い合わせください未管理パッケージはアップグレードできないため各パッケージバージョンは単に配布用コンポーネントのセットですパッケージバージョンは管理パッケージでより大きな意味を持ちますパッケージは異なるバージョンで異なる動作をします公開者はパッケージバージョンを使用してパッケージを使用する既存の連携に影響を与えることなく後続のパッケージバージョンをリリースすることにより管理パッケージのコンポーネントを発展させることができます
既存の登録ユーザが新しいパッケージをインストールした場合パッケージ内の各コンポーネントのインスタンスは 1 つだけですがコンポーネントは古いバージョンをエミュレートできますたとえば登録ユーザはApexクラスを含む管理パッケージを使用するとします公開者が Apex クラスのメソッドを廃止し新しいパッケージをリリースする場合でも新しいバージョンをインストールした後登録ユーザは Apex クラスのインスタンスを 1 つだけ使用できますただしこのApexクラスは古いバージョンの廃止されたメソッドを参照するコードの以前のバージョンをエミュレートできます
管理パッケージで Apex を開発する場合次の点に注意してください
bull 管理パッケージは固有の名前空間を持ちますこの名前空間はインストール先の組織において名前の重複を防ぐため自動的にクラスメソッド変数などの前に追加されます
bull 管理パッケージの一部であるApexコードは自動的に隠されインストール先の組織内では見ることができません唯一の例外としてグローバルとして宣言されているメソッドですそのようなメソッドの署名はインストールを行う組織でも参照できます
bull パッケージ管理者はdeprecatedアノテーションを使用して今後のリリースの管理パッケージでは参照できないメソッドクラス例外列挙インタフェース変数を指定することができます管理パッケージのコードをリファクタリングする場合に役立ちます
bull システムメソッドを runAsを使用してパッケージバージョンコンテキストを異なるパッケージバージョンに変更するテストメソッドを作成できます
bull クラスが「管理-リリース済み」パッケージバージョンでアップロードされた後にインストールまたは抽象クラスまたは仮想クラスにメソッドを追加することはできません
bull 明示的に名前空間を参照する非管理パッケージに含まれる Apex スクリプトはアップロードできません
Apex の廃止
パッケージ管理者はdeprecatedアノテーションを使用して今後のリリースの管理パッケージでは参照できないメソッドクラス例外列挙インタフェース変数を指定することができます管理パッケージのコードをリファクタリングする場合に役立ちます別のパッケージを「管理 - リリース済み」でアップロードすると最新のパッケージバージョンをインストールする新しい登録ユーザは非推奨の要素を確認できませんがその要素は既存の登録ユーザおよび API 連携で機能し続けますメソッドまたはクラスなど破棄された項目は最初はパッケージ開発者によって参照できます
管理パッケージでの Apex の開発 Version 180 | パッケージバージョン | 166
メモ 非管理パッケージの Apex クラスまたはトリガの deprecatedアノテーションは使用できません
パッケージ開発者は異なる Salesforcecom 組織のユーザのパイロットユーザによる評価およびフィードバックのために管理-ベータパッケージバージョンを使用できます開発者がApex識別子を廃止しあるバージョンのパッケージを「管理 - ベータ」としてアップロードしてもパッケージバージョンをインストールした登録ユーザはパッケージバージョンの廃止された識別子を参照できますパッケージ開発者がその後「管理-リリース済み」パッケージバージョンをアップロードした場合インストールした後登録ユーザにはパッケージバージョンの廃止された識別子は表示されません
パッケージバージョンの動作
パッケージコンポーネントは異なるパッケージバージョンで異なる動作をします動作のバージョニングにより新しいコンポーネントをパッケージに追加し既存のコンポーネントを調整することができますコードは既存の登録者にもシームレスに機能しますパッケージ開発者が新しいコンポーネントをパッケージに追加し新しいパッケージバージョンをアップロードした場合新しいパッケージバージョンをインストールした登録者は新しいコンポーネントを使用できるようになります
Apex コードの動作のバージョニングApex には特殊構文がありパッケージ開発者はクラスおよびトリガで異なるバージョンに異なる動作をさせる条件付きロジックを使用できますこれによりパッケージ開発者はコードをアップグレードしても以前のパッケージバージョンのクラスおよびトリガの既存の動作を継続してサポートできます
登録者が複数のバージョンのパッケージをインストールしパッケージ内の Apex クラスまたはトリガを参照するコードを記述する場合参照しているバージョンを選択する必要がありますパッケージ内で参照しているApex コード内で参照を作成する呼び出し Apex コードのバージョン設定に基づき異なるコードパスを条件付きで実行できます呼び出しコードのパッケージバージョン設定はPackageVersionRequestオブジェクトを使用してパッケージコード内で決定できますパッケージ開発者はこのオブジェクトおよび付随するメソッドを使用して要求コンテキストを決定しさまざまなバージョンのパッケージの異なる動作を示すことができます
次の例は異なるパッケージバージョンのトリガの動作を示します
trigger oppValidation on Opportunity (before insert before update)
for(Opportunity o Triggernew)
New validation added in package version 15 Applies to all version of the managedpackage except 10 If(PackageVersionRequestisGreaterThan(PackageVersion10))If(oProbability gt= 50 ampamp oDescription == NULL) oaddError(All deals over 50 require adescription)
Validation applies to all versions of the managed package If(oIsWon == true ampampoLeadSource == NULL) oaddError(A lead source must be provided for all Closed Won deals)
パッケージバージョンを処理するメソッドの詳細は「Package メソッド (ページ 284)」を参照してください
管理パッケージでの Apex の開発 Version 180 | パッケージバージョンの動作 | 167
メモ 非管理パッケージではPackageVersionRequestオブジェクトは使用できません
インストールパッケージのあるクラスがパッケージの別のクラスのメソッドを呼び出す場合要求コンテキストは保持されますたとえば登録者は CountryUtil クラスおよび ContinentUtil Apex クラスを含む GeoReports パッケージをインストールしたとします登録者は GeoReportsEx クラスを新規作成しバージョン設定を使用してバージョン 23 の GeoReports パッケージにバインドしますGeoReportsEx が CountryUtil のメソッドを内部的に呼び出す ContinentUtil のメソッドを呼び出すと 要求コンテキストは ContinentUtil から CountryUtil に反映されCountryUtil PackageVersionRequestの変数はバージョン 23 の GeoReports パッケージを参照します
バージョニングされていない Apex コードの項目パッケージバージョンでいくつかのApex項目の動作を変更できますたとえば新しい登録者が後続のバージョンのパッケージを参照できないようメソッドを廃止できます
ただし次のリストの修飾子キーワードアノテーションについてはバージョニングできませんパッケージ開発者が次の修飾子キーワードまたはアノテーションのいずれかを変更すると変更はすべてのパッケージバージョンに反映されます
管理パッケージの Apex コードで使用される場合これらの項目のいくつかに行うことができる変更には制限事項があります
パッケージ開発者は次の項目を追加または削除できます
bull future
bull isTest
bull with sharing
bull without sharing
bull transient
パッケージ開発者は次の項目に制限付きで変更を行うことができます
bull private globalに変更できますbull public globalに変更できますbull protected globalに変更できますbull abstract virtualに変更できますが削除できませんbull final 削除できますが追加はできません
パッケージ開発者は次の項目の追加または変更することはできません
bull global
bull virtual
パッケージ開発者は webServiceキーワードを追加できますがいったん追加すると削除することはできません
メモ 管理パッケージコードの webServiceメソッドまたは変数を廃止することはできません
管理パッケージでの Apex の開発 Version 180 | バージョニングされていない Apex コードの項目 | 168
パッケージバージョンの動作のテスト異なるパッケージバージョンの Apex クラスまたはトリガの動作を変更する場合異なるパッケージバージョンで期待されているようにコードをテストすることが重要ですシステムメソッドをrunAsを使用してパッケージバージョンコンテキストを異なるパッケージバージョンに変更するテストメソッドを作成できますrunAs
はテストメソッドでのみ使用できますこのメソッドはテストメソッドのPackageVersionRequestオブジェクトとして効果的に設定します
次の例は異なるパッケージバージョンの異なる動作のトリガを示します
trigger oppValidation on Opportunity (before insert before update)
for(Opportunity o Triggernew)
Add a new validation to the package Applies to versions of the managed package greaterthan 10 If(PackageVersionRequestisGreaterThan(PackageVersion10)) If(oProbabilitygt= 50 ampamp oDescription == NULL) oaddError(All deals over 50 require a description)
Add a new validation to the package This validation applies to all versions of themanaged packageIf(oIsWon == true ampamp oLeadSource == NULL) oaddError(A lead source mustbe provided for all Closed Won deals)
次のテストクラスはトリガの動作を確認します
isTest public class OppTriggerTests
static testMethod void testOppValidation()
Set up 50 opportunity with no description Opportunity o = new Opportunity() oName =Test Job oProbability = 50 oStageName = Prospect oCloseDate = Systemtoday()
Test running as latest package version try insert o catch(SystemDMLException e)Systemassert( egetMessage()contains( All deals over 50 require a description)egetMessage())
Run test as managed package version 10 SystemrunAs(PackageVersion10) try inserto catch(SystemDMLException e) Systemassert(false egetMessage())
Set up a closed won opportunity with no lead source o = new Opportunity() oName = TestJob oProbability = 50 oStageName = Prospect oCloseDate = Systemtoday() oStageName= Closed Won
Test running as latest package version try insert o catch(SystemDMLException e)Systemassert( egetMessage()contains( A lead source must be provided for all Closed Wondeals) egetMessage())
Run test as managed package version 10 SystemrunAs(PackageVersion10) try inserto catch(SystemDMLException e) Systemassert( egetMessage()contains( A lead sourcemust be provided for all Closed Won deals) egetMessage())
管理パッケージでの Apex の開発 Version 180 | パッケージバージョンの動作のテスト | 169
第 10 章
Apex メソッドの Web サービスとしての公開
外部アプリケーションがコードおよびアプリケーションにアクセスできるようApex メソッドを公開できますApex メソッドを公開するにはWebService メソッドを使用します
トピック
bull WebService メソッド
ヒント Apex Web サービスを使用すると外部アプリケーションは Web サービスを使用して Apex メソッドを呼び出すことができますApex コールアウトを使用するとApex は外部 Webまたは HTTP サービスを呼び出すことができます
WebService メソッド
ApexクラスメソッドはカスタムのForcecom Web サービスAPIコールとしての表示が可能ですこれにより外部アプリケーションが Apex Web サービスを実行しSalesforcecom でアクションを実行できるようになりますこれらのメソッドの定義には webServiceキーワードを使用します例
global class MyWebService webService static Id makeContact(String lastName Account a) Contact c = new Contact(lastName = Weissman AccountId = aId) insert c return cid
外部アプリケーションの開発者はクラスの WSDL を生成してwebServiceメソッドを含む Apex クラスと統合できますApex クラス詳細ページから WSDL を生成する手順は次のとおりです
1 アプリケーションで[設定] [開発] [Apex クラス] をクリックします2 webServiceメソッドを含むクラス名をクリックします3 [WSDL の生成] をクリックします
WebService メソッドによるデータの公開カスタム webServiceメソッドの呼び出しには必ず System コンテキストを使用しますその結果現在のユーザーの証明書は使用されずこれらのメソッドにアクセスできるユーザーが権限項目レベルのセキュリティ共有ルールに関係なく全機能を使用できますwebServiceキーワードでメソッドを公開する開発者は機密情報データを不注意に公開しないよう注意する必要があります
警告 with sharingキーワードを使用して定義されたクラスにメソッドが含まれていない場合webServiceキーワードにより API を介して公開する Apex クラスメソッドではレコードのオブジェクト権限項目レベルのセキュリティ共有ルールを参照しません with sharingを使用して定義されたクラスだけが現在のユーザの共有ルールに関係します
WebServiceキーワード使用に関する考慮事項webServiceキーワードを使用する場合次の考慮事項について注意してください
bull クラスの定義には webServiceキーワードを使用できませんただし最上位の外部クラスメソッドと内部クラスメソッドを定義するために使用できます
bull webServiceキーワードを使用してインターフェースを定義またはインターフェースのメソッドおよび変数を定義することはできません
bull システム定義の enum は Web サービスメソッドで使用することはできませんbull トリガのメソッドを定義できないためトリガに webServiceキーワードを使用できませんbull webServiceキーワードと共に定義されているメソッドを含むすべてのクラスは globalとして宣言する必要
がありますメソッドまたは内部クラスを globalとして宣言した場合外部のトップレベルクラスもglobalとして宣言する必要があります
bull webServiceキーワードで定義されるメソッドは本質的にグローバルですこれらのメソッドをクラスにアクセスできる Apex スクリプトで使用できますwebServiceキーワードをglobalより多くのアクセスを可能にするアクセス変更子の種類として検討することができます
bull webServiceキーワードを使用するメソッドを staticとして定義する必要があります
Apex メソッドの Web サービスとしての公開 Version 180 | WebService メソッド | 171
bull 管理パッケージコードの webServiceメソッドまたは変数を廃止することはできませんbull 特定の Apex 要素に SOAP アナログがないためwebServiceキーワードで定義されたメソッドは次の要素
をパラメータとして使用することはできませんこれらの要素はメソッド内で使用できますが戻り値としてマークすることはできません
- Map- Sets- Pattern オブジェクト- Matcher オブジェクト- 例外オブジェクト
bull webServiceキーワードはWeb サービスの一部として公開するメンバー変数で使用する必要がありますこれらのメンバー変数を staticとマークすることはできません
bull Salesforcecom はアクセスが Restrictedになっている AppExchange パッケージからの Web サービスへのアクセスと executeanonymous要求を拒否します
bull 項目に割り当てた文字列値が長すぎる場合APIバージョン 150 以上を使用して保存 (コンパイル) したApexクラスにはランタイムエラーが発生します
次の例はWeb サービス変数と Web サービスメソッドを持つクラスを示しています
global class SpecialAccounts
global class AccountInfo WebService String AcctName WebService Integer AcctNumber
WebService static Account createAccount(AccountInfo info) Account acct = new Account()acctName = infoAcctName acctAccountNumber = StringvalueOf(infoAcctNumber) insertacct return acct
WebService static Id [] createAccounts(Account parent Account child Account grandChild)
insert parent childparentId = parentId insert child grandChildparentId = childIdinsert grandChild
Id [] results = new Id[3] results[0] = parentId results[1] = childId results[2] =grandChildId return results
TestMethod static void testAccountCreate() AccountInfo info = new AccountInfo()infoAcctName = Manoj Cheenath infoAcctNumber = 12345 Account acct =SpecialAccountscreateAccount(info) Systemassert(acct = null)
AJAX を使用してこの Web サービスを呼び出すことができます詳細は「AJAX のApex」 (ページ 82)を参照してください
Web サービスメソッドのオーバーロードSOAP およびWSDL ではメソッドをオーバーロードできませんその結果ApexではwebServiceキーワードでマークされた 2 つのメソッドに同じ名前を付けることはできません同じクラスで同じ名前を持つWeb サービスメソッドを使用するとコンパイル時エラーが発生します
Apex メソッドの Web サービスとしての公開 Version 180 | Web サービスメソッドのオーバーロード | 172
第 11 章
Apex を使用したコールアウトの呼び出し
Apex コールアウトを使用して外部 Web サービスへのコールを作成またはApexスクリプトから HTTP 要求を送信して応答を受信すること
トピック
bull リモート サイト設定の追加 によってApex を外部サービスとを密接に統合することができますbull SOAP サービス WSDL ドキュメ
ントからのクラスの定義Apex はSOAP および WSDLまたは HTTP サービス (RESTful サービス) を使用する Web サービスと統合できます
bull HTTP コールアウトの呼び出し メモ Apex コールアウトが外部サイトを呼び出す前にそのサイトを [リモートサイトの設定] ページで登録する必要がありまbull 証明書の使用
bull コールアウトの制限 す登録しない場合コールアウトが失敗しますSalesforcecomでは認証されていないネットワーク アドレスへのコールが行われないようにします
2 種類のコールアウトの詳細は次の項目を参照してください
bull SOAP サービス WSDL ドキュメントからのクラスの定義 (ページ174)
bull HTTP コールアウトの呼び出し (ページ 181)
ヒント コールアウトによってApex は外部 Web または HTTPサービスを呼び出すことができますApex Web サービスを使用すると外部アプリケーションはWeb サービスを使用して Apexメソッドを呼び出すことができます
リモートサイト設定の追加
Apex コールアウトが外部サイトを呼び出す前にそのサイトを [リモートサイトの設定] ページで登録する必要があります登録しない場合コールアウトが失敗しますSalesforcecomでは認証されていないネットワークアドレスへのコールが行われないようにします
リモートサイト設定を追加する手順は次のとおりです
1 [設定] [セキュリティのコントロール] [リモートサイト設定] をクリックします2 [新規リモートサイト] をクリックします3 [リモートサイト名]には分かりやすい名前を入力してください4 リモートサイトの URL を入力します5 必要に応じてサイトの説明を入力します6 [保存] をクリックします
SOAP サービス WSDL ドキュメントからのクラスの定義
クラスはローカルハードドライブやネットワークに保管されている WSDL ドキュメントから自動的に生成されます WSDL ドキュメントを使ってクラスを作成すると開発者は Apex スクリプトの中で外部 Web サービスを呼び出すことができます
メモ 可能な場合にはアウトバウンドメッセージを使用して統合ソリューションを処理します必要な場合に限りサードパーティの Web サービスの呼び出しを使用します
WSDL から Apex クラスを作成する手順は次のとおりです
1 アプリケーションで[設定] [開発] [Apex クラス] をクリックします2 [WSDL からの生成] をクリックします3 [参照] をクリックしてローカルハードドライブまたはネットワーク上の WSDL ドキュメントを選択する
かフルパスを入力しますこの WSDL ドキュメントが作成する Apex クラスの基礎となりますが1 MB以下である必要があります
メモ
指定した WSDL ドキュメントに送信ポートを参照する SOAP エンドポイントの場所が記載されている場合があります
セキュリティ上の理由からSalesforcecom では指定できる送信ポートを次の 1 つに制限します
bull 80 このポートはHTTP 接続のみを受け付けますbull 443 このポートはHTTPS 接続のみを受け付けますbull 7000-10000 (7000 と 10000 も含む) これらのポートはHTTP 接続または HTTPS 接続を受け付け
ます
4 [WSDL を解析] をクリックしてWSDL ドキュメントの内容を確認しますアプリケーションがWSDLドキュメント内の名前空間それぞれのデフォルトクラス名を生成しエラーがあれば報告しますWSDL に
Apex を使用したコールアウトの呼び出し Version 180 | リモート サイト設定の追加 | 174
Apex クラスがサポートしていないスキーマタイプまたはスキーマ構造が含まれているか結果生成されるクラス名が100000文字というApexクラスの制限を超える場合には解析は失敗しますたとえばSalesforcecomSOAP API WSDL は解析できません
5 必要に応じてそのクラス名を変更しますそれぞれの名前空間に対して同じクラス名を使用することにより1 つのクラスに複数の WSDL 名前空間を保存できますがApex クラスは合計 100000 文字以内にしてください
6 [Apex の生成] をクリックしますウィザードの最終ページにはどのクラスが正常に生成されたか他のクラスからのエラーがあればそれも含めて表示されます生成が成功した場合には生成されたコードを表示するためのリンクも示されます
正常に生成された Apex クラスにはWSDL ドキュメントで示されていたサードパーティ Web サービスを呼び出すスタブとタイプクラスが含まれていますこれらのクラスによりApex から外部の Web サービスを呼び出すことができますWeb サービスコールの SOAP 要求および応答は 1 MB 以下に制限されています
生成された Apex については次の点にご注意ください
bull WSDL ドキュメントに Apex の予約語が含まれている場合はApex クラスが生成されるときにその語の後ろに「_x」が付きますたとえばWSDL ドキュメントに「limit」があると生成されるApexクラスでは「limit_x」になります「予約キーワード (ページ397)」を参照してくださいApex変数名でサポートされていない WSDL の要素名の文字の処理の詳細については「WSDL 使用についての考慮事項 (ページ 180)」を参照してください
bull WSDL の操作に複数の要素がある出力メッセージがある場合生成された Apex は内部クラスの要素をラップしますWSDL 操作を示す Apex メソッドは各要素の代わりに内部クラスを返します
WSDL からクラスを生成したあとWSDL で参照される外部サービスを呼び出すことができます
メモ このトピックの残りのサンプルを使用する前に「生成されるコードについて」から Apex クラスdocSampleClassをコピーして組織に追加する必要があります
外部サービスの呼び出しWSDL ドキュメントを使用して Apex クラスを生成した後外部サービスを呼び出すにはApex スクリプトにstub のインスタンスを作成してそれにメソッドをコールしますたとえばApexから StrikeIron IP アドレス検索サービスを呼び出すために次のようなスクリプトを作成することができます
stub を作成 strikeironIplookupDNSSoap dns = new strikeironIplookupDNSSoap()
ライセンスのヘッダーを設定 dnsLicenseInfo = new strikeironLicenseInfo()dnsLicenseInfoRegisteredUser = new strikeironRegisteredUser()dnsLicenseInfoRegisteredUserUserID = youcompanycomdnsLicenseInfoRegisteredUserPassword = your-password
Web サービスコールを作成 strikeironIplookupDNSInfo info = dnsDNSLookup(wwwmynamecom)
HTTP ヘッダーのサポートWeb サービスコールアウトに HTTP ヘッダーを設定できるようになりましたたとえばこの機能を使用して認可ヘッダーに Cookie の値を設定できますHTTP ヘッダーを設定するにはinputHttpHeaders_xおよびoutputHttpHeaders_xをスタブに追加します
Apex を使用したコールアウトの呼び出し Version 180 | 外部サービスの呼び出し | 175
メモ API バージョン 160 より前ではコールアウト HTTP 応答はコンテンツタイプのヘッダーに関係なく UTF-8 を使用してデコードされますAPI バージョン 170 移行ではHTTP 応答はコンテンツタイプのヘッダーで指定されたエンコードを使用してデコードされます
次のサンプルでは「生成されるコードについて」 (ページ178)のサンプルWSDL ファイルを使用しています
Web サービスコールアウトの HTTP ヘッダーの送信
docSampleDocSamplePort stub = new docSampleDocSamplePort() stubinputHttpHeaders_x = newMapltString Stringgt()
基本認証ヘッダーの設定
stubinputHttpHeaders_xput(Authorization Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==)
クッキーヘッダーの設定 stubinputHttpHeaders_xput(Cookie name=value)
カスタム HTTP ヘッダーの設定 stubinputHttpHeaders_xput(myHeader myValue)
String input = This is the input string String output = stubEchoString(input)
inputHttpHeaders_xの値を指定すると標準ヘッダーセットを上書きします
Web サービスコールアウトレスポンスからの HTTP レスポンスヘッダーのアクセス
docSampleDocSamplePort stub = new docSampleDocSamplePort() stuboutputHttpHeaders_x =new MapltString Stringgt() String input = This is the input string String output =stubEchoString(input)
クッキーヘッダーの取得 String cookie = stuboutputHttpHeaders_xget(Set-Cookie)
カスタムヘッダーの取得 String myHeader = stuboutputHttpHeaders_xget(My-Header)
outputHttpHeaders_xのデフォルト値は null ですoutputHttpHeaders_xを設定してからレスポンスのヘッダーの内容にアクセスできます
サポートされた WSDL 機能Apex ではドキュメントリテラルでラップした WSDL スタイルと組み込みデータ型のみをサポートしています
Apex タイプスキーマタイプStringxsdanyURI
Booleanxsdboolean
Datexsddate
DatetimexsddateTime
Doublexsddouble
Doublexsdfloat
Integerxsdint
Apex を使用したコールアウトの呼び出し Version 180 | サポートされた WSDL 機能 | 176
Apex タイプスキーマタイプIntegerxsdinteger
Stringxsdlanguage
Longxsdlong
StringxsdName
StringxsdNCName
IntegerxsdnonNegativeInteger
StringxsdNMTOKEN
StringxsdNMTOKENS
StringxsdnormalizedString
StringxsdNOTATION
IntegerxsdpositiveInteger
StringxsdQName
Integerxsdshort
Stringxsdstring
Datetimexsdtime
Stringxsdtoken
IntegerxsdunsignedInt
LongxsdunsignedLong
IntegerxsdunsignedShort
メモ Salesforcecom データ型 anyType はAPI バージョン 150 以降を使用して保存される Apex コードを生成するときに使用する WSDL ではサポートされませんAPI バージョン 140 以前を使用して保存されるコードではanyType は String にマッピングされます
Apex では次のスキーマ構造をサポートしています
bull API バージョン 150 以上を使用して保存した Apex コードの xsdall
bull API バージョン 150 以上を使用して保存した Apex コードの xsdannotation
bull API バージョン 150 以上を使用して保存した Apex コードの xsdattribute
bull API バージョン 150 以上を使用して保存した Apex コードの xsdchoice
bull xsdelementAPI バージョン 150 以上を使用して保存した Apex コードではref属性が次の制限付きでサポートされます
- 名前空間を指定して異なる名前空間で refをコールできます- グローバル要素は refを使用できません- 要素に refが含まれている場合nameも typeを含むことはできません
bull xsdsequence
Apex を使用したコールアウトの呼び出し Version 180 | サポートされた WSDL 機能 | 177
次のデータ型はコールインとして使用されている場合つまり外部Web サービスがApex Web サービスメソッドをコールする場合にのみサポートされていますこれらのデータ型はコールアウトとして使用されている場合つまり Apex Web サービスメソッドが外部 Web サービスをコールする場合はサポートされていません
bull blobbull decimalbull enum
Apex は次のようなその他の WSDL コンストラクタデータ型サービスをサポートしていません
bull RPCエンコード化サービスbull 複数の portTypes複数のサービスまたは複数のバインドを含む WSDL サービスbull 外部スキーマをインポートする WSDL ファイルたとえば次の WSDL フラグメントはサポートされてい
ない外部スキーマをインポートします
ltwsdltypesgt ltxsdschema elementFormDefault=qualifiedtargetNamespace=https3amazonawscomdoc2006-03-01gt ltxsdincludeschemaLocation=AmazonS3xsdgt ltxsdschemagt ltwsdltypesgt
ただし同じスキーマ内のインポートはサポートされています次の例では外部 WSDL は変換しているWSDL に貼り付けられます
ltwsdltypesgt ltxsdschema xmlnstns=https3amazonawscomdoc2006-03-01xmlnsxsd=httpwwww3org2001XMLSchema elementFormDefault=qualifiedtargetNamespace=https3amazonawscomdoc2006-03-01gt
ltxsdelement name=CreateBucketgt ltxsdcomplexTypegt ltxsdsequencegt [] ltxsdschemagtltwsdltypesgt
bull 前の表に記載されていないスキーマタイプbull Salesforcecom WSDL などサイズ制限をこえた WSDL
生成されるコードについて次の例ではWSDL ドキュメントから Apex クラスがどのように作成されるかを示します次のコードではサンプル WSDL ドキュメントを示します
ltwsdldefinitions xmlnshttp=httpschemasxmlsoaporgwsdlhttpxmlnssoap=httpschemasxmlsoaporgwsdlsoap xmlnss=httpwwww3org2001XMLSchemaxmlnssoapenc=httpschemasxmlsoaporgsoapencodingxmlnstns=httpdocsamplecomdocSample targetNamespace=httpdocsamplecomdocSamplexmlnswsdl=httpschemasxmlsoaporgwsdlgt
lt-- Above the schema targetNamespace maps to the Apex class name --gt
lt-- Below the type definitions for the parameters are listedEach complexType and simpleTypeparameteris mapped to an Apex class inside the parent class for the WSDLThen each elementin the complexType is mapped to a public field inside the class --gt
ltwsdltypesgt ltsschema elementFormDefault=qualifiedtargetNamespace=httpdocsamplecomdocSamplegt ltselement name=EchoStringgtltscomplexTypegt ltssequencegt ltselement minOccurs=0 maxOccurs=1 name=inputtype=sstring gt ltssequencegt ltscomplexTypegt ltselementgt ltselementname=EchoStringResponsegt ltscomplexTypegt ltssequencegt ltselement minOccurs=0 maxOccurs=1name=EchoStringResult type=sstring gt ltssequencegt ltscomplexTypegt ltselementgtltsschemagt ltwsdltypesgt
Apex を使用したコールアウトの呼び出し Version 180 | 生成されるコードについて | 178
lt--The stub below defines operations --gt
ltwsdlmessage name=EchoStringSoapIngt ltwsdlpart name=parameters element=tnsEchoStringgt ltwsdlmessagegt ltwsdlmessage name=EchoStringSoapOutgt ltwsdlpart name=parameterselement=tnsEchoStringResponse gt ltwsdlmessagegt ltwsdlportType name=DocSamplePortTypegtltwsdloperation name=EchoStringgt ltwsdlinput message=tnsEchoStringSoapIn gt ltwsdloutputmessage=tnsEchoStringSoapOut gt ltwsdloperationgt ltwsdlportTypegt
lt--The code below defines how the types map to SOAP --gt
ltwsdlbinding name=DocSampleBinding type=tnsDocSamplePortTypegt ltwsdloperationname=EchoStringgt ltsoapoperationsoapAction=urndotnetcallouttestsoapsforcecomEchoString style=document gtltwsdlinputgt ltsoapbody use=literal gt ltwsdlinputgt ltwsdloutputgt ltsoapbody use=literalgt ltwsdloutputgt ltwsdloperationgt ltwsdlbindinggt
lt-- Finally the code below defines the endpoint which maps to the endpoint in the class--gt
ltwsdlservice name=DocSamplegt ltwsdlport name=DocSamplePortbinding=tnsDocSampleBindinggt ltsoapaddresslocation=httpwwwqaresponderinfoWebServicesDocSampleasmx gt ltwsdlportgtltwsdlservicegt ltwsdldefinitionsgt
この WSDL ドキュメントから次の Apex クラスを生成することができます
Generated by wsdl2apex
public class docSample
public class EchoStringResponse_element
public String EchoStringResult
private String[] EchoStringResult_type_info = new String[] EchoStringResulthttpwwww3org2001XMLSchema string01false
private String[] apex_schema_type_info = new String[] httpdocsamplecomdocSampletrue
private String[] field_order_type_info = new String[] EchoStringResult
public class DocSamplePort
public String endpoint_x = httpwwwqaresponderinfoWebServicesDocSampleasmx
private String[] ns_map_type_info = new String[] httpdocsamplecomdocSampledocSample
public String EchoString(String input) docSampleEchoString_element request_x = newdocSampleEchoString_element() docSampleEchoStringResponse_element response_xrequest_xinput = input MapltString docSampleEchoStringResponse_elementgt response_map_x= new MapltString docSampleEchoStringResponse_elementgt() response_map_xput(response_xresponse_x) WebServiceCalloutinvoke( this request_x response_map_x newString[]endpoint_x urndotnetcallouttestsoapsforcecomEchoStringhttpdocsamplecomdocSample EchoString httpdocsamplecomdocSampleEchoStringResponse docSampleEchoStringResponse_element ) response_x =response_map_xget(response_x) return response_xEchoStringResult
public class EchoString_element
public String input private String[] input_type_info = new String[] inputhttpwwww3org2001XMLSchema string01false private String[]
Apex を使用したコールアウトの呼び出し Version 180 | 生成されるコードについて | 179
apex_schema_type_info = new String[] httpdocsamplecomdocSample true privateString[] field_order_type_info = new String[]input
元の WSDL ドキュメントからの次のマッピングに注意してください
bull WSDL ターゲット名前空間は Apex クラス名にマップしますbull 複雑なデータ型はクラスになりますデータ型の各要素はクラスの公開項目ですbull WSDL ポート名は stub クラスにマップしますbull WSDL の各処理は公開メソッドにマップします
上記で生成されたクラスを使用して外部 Web サービスを呼び出すことができます次のコードは外部サーバーで echoStringメソッドをどのようにコールするかを示しています
docSampleDocSamplePort stub = new docSampleDocSamplePort() String input = 入力文字列ですString output = stubEchoString(input)
WSDL 使用についての考慮事項WSDL から Apex クラスを生成する場合次の点に注意してください
ヘッダーのマッピング
WSDL ドキュメントで定義されているヘッダーは生成されたクラスの stub の公開項目となりますこれはAJAX Toolkit および Net と同様です
ランタイムイベントについて
Apex スクリプトが外部サービスへのコールアウトを作成している場合次のことがチェックされます
bull 要求サイズが 1 MB 未満であることbull 応答サイズが 1 MB 未満であることbull HTTP 要求またはWeb サービスコールを作成する場合のタイムアウト制限の詳細は「コールアウトの制限
(ページ 184)」を参照してくださいbull Apex クラスでは循環参照が無効であることbull Salesforcecom ドメインへの複数のループバック接続が無効であることbull エンドポイントにアクセスする場合[設定] [セキュリティ] [リモートサイト設定] で登録することbull データベース接続が停止しないようトランザクションが開かれないこと
変数名でサポートされていない文字について
WSDL ファイルにはApex変数名で使用できない要素名を使用することができますWSDL ファイルからApex変数名を生成する場合次のルールが適用されます
bull 要素名の最初の文字がアルファベットでない場合x文字が生成された Apex 変数名の先頭に追加されますbull 要素名の最後の文字が Apex 変数名で使用できない場合x文字が生成された Apex 変数名に追加されますbull 要素名に Apex 変数名で使用できない文字が含まれている場合その文字は (_) 文字に置き換えられますbull 要素名に Apex 変数名で使用できない文字が 1 行に 2 文字含まれている場合最初の文字はアンダースコア
(_) 文字に置き換えられ2 番目の文字は x文字に置き換えられますこれによりApex では使用できない 2つの連続したアンダースコアで変数名が生成されないようにします
Apex を使用したコールアウトの呼び出し Version 180 | WSDL 使用についての考慮事項 | 180
bull 2 つのパラメータa_および a_xを使用する処理があるとします生成されたApexには 2 つの変数がありいずれもa_xという名前ですクラスはコンパイルしません手動でApexを編集しいずれかの変数名を変更する必要があります
WSDL ファイルから生成したクラスのデバッグ
Forcecom Web サービスNetおよび Axis を使用してコードをテストします他のツールを使用する場合問題が発生する場合があります
デバッグヘッダーを使用して要求の XML を返しSOAP メッセージに応答して問題の検出を行います詳細は「Apex の Web サービス API コールと SOAP ヘッダー」 (ページ 406)を参照してください
HTTP コールアウトの呼び出し
Apex ではHTTP サービスを使用しGETPOSTPUTおよび DELETE のような HTTP 要求を作成する組み込みクラスをいくつか提供します
これらの HTTP クラスを使用してREST ベースのサービスに統合できますWSDL からApexスクリプトを生成する別のオプションとしてSOAP ベースの Web サービスに登場することもできますWSDL で開始する代わりに HTTP クラスを使用して要求および応答の SOAP メッセージの構造をより高度に処理します
詳細およびサンプルは「HTTP (RESTful) サービスクラス」 (ページ349)を参照してくださいまたForcecomToolkit for Google Data APIs を HTTP コールアウトの使用を拡張します
証明書の使用
コールアウトによって Salesforcecomで生成されたまたは認証機関 (CA) が署名した証明書を送信して双方向の SSL 認証を使用できますコールアウトの対象が証明書を受け取るとセキュリティが拡張され証明書を使用して要求をキーストアに対して認証できます
コールアウトの双方向 SSL 認証を有効にする手順は次のとおりです
1 証明書を生成します2 証明書をコードと統合します「SOAP サービスでの証明書の使用」および「HTTP 要求での証明書の使用」
を参照してください3 サードパーティに接続し自己署名の証明書を使用している場合Salesforcecom 証明書を共有し証明書を
キーストアに追加できるようにします組織内で使用される別のアプリケーションに接続している場合クライアント証明書を要求するようWeb またはアプリケーションサーバーを設定しますこのプロセスは使用する Web サーバーまたはアプリケーション サーバーの種類によって異なりますJava の Tomcat を使用して両方向 SSL を設定する方法についてその例がhttpwwwvorburgerchblog1200608setting-up-two-way-mutual-ssl-withhtml のブログに投稿されています
4 コールアウトのリモートサイト設定を設定しますApexコールアウトが外部サイトを呼び出す前にそのサイトを [リモートサイトの設定] ページで登録する必要があります登録しない場合コールアウトが失敗します
Apex を使用したコールアウトの呼び出し Version 180 | HTTP コールアウトの呼び出し | 181
証明書の生成Salesforcecom で生成された自己署名証明書または認証機関 (CA) で署名された証明書を使用できますコールアウトの証明書を生成する手順は次のとおりです
1 外部 Web サイトが自己署名の証明書を承認するかどうかまたは CA の署名が必要かどうかに基づいて作成する証明書の種類を決定します証明書を作成した後に証明書の種類を変更することはできません
2 [設定] [セキュリティコントロール] [証明書およびキーの管理] をクリックし[自己署名証明書の作成]または [CA 署名の証明書を作成] をクリックします証明書の種類を選択します後で変更することはできません
3 Salesforcecom 証明書の説明ラベルを入力しますこの名前は証明書を参照する場合主に管理者によって使用されます
4 一意名を入力します入力した証明書ラベルに従って名前が自動的に入力されますこの名前はアンダースコアと英数字のみを含み組織内で一意の名前にする必要があります最初は文字であることスペースは使用しない最後にアンダースコアを使用しない2 つ続けてアンダースコアを使用しないという制約がありますForcecom Web サービス API または Apex を使用して証明書を参照する場合一意名を使用します
5 生成した証明書およびキーのキーサイズを選択します1024を選択すると1024 ビットのキーを使用する証明書を生成し1 年間有効です2048を選択すると2048 ビットのキーを使用する証明書を生成し2 年間有効ですセキュリティ上の理由により2048を指定することをお勧めします
メモ Salesforcecom 証明書を保存するとキーサイズは変更できません
6 CA 署名証明書を作成している場合次の情報も入力する必要がありますこれらの項目を結合して一意の証明書を生成します
説明項目
署名付き証明書を要求する会社の完全修飾名形式は通常httpwwwmycompanycomとなります
Common Name
証明書に関連する電子メールアドレスEmail Address
会社の法律上の名前Company
マーケティング会計など証明書を使用する会社の部署
Department
会社がある都市City
会社がある州State
会社がある国を示す 2 文字のコードアメリカ合衆国の場合値は USです
Country Code
7 [保存] をクリックします
正常に Salesforcecom 証明書を保存した後証明書および対応するキーが自動的に生成されます
CA 署名証明書を作成した後使用する前に署名付き証明書をアップロードする必要がありますSalesforcecomオンラインヘルプの「CA 署名証明書のアップロード」を参照してください
Apex を使用したコールアウトの呼び出し Version 180 | 証明書の生成 | 182
SOAP サービスでの証明書の使用Salesforcecomで証明書を生成した後SOAP Web サービスへのコールアウトの双方向認証をサポートできます
証明書を Apex を統合する手順は次のとおりです
1 他社から Web サービスから WSDL を受け取るか接続するアプリケーションから生成します2 Web サービスの WSDL から Apex クラスを生成します「SOAP サービス WSDL ドキュメントからのクラ
スの定義 (ページ 174)」を参照してください3 生成された Apex クラスにはWSDL ドキュメントで示されていた他社の Web サービスを呼び出すスタブが
含まれていますApexクラスを編集し値をスタブクラスのインスタンスのclientCertName_x変数に割り当てます値は [設定] [セキュリティコントロール] [証明書とキーの管理] を使用して生成した証明書の一意名と一致する必要があります
次の例では前の手順の最後のステップを説明し「生成されるコードについて」 (ページ178)のサンプルWSDLファイルを使用していますこの例ではDocSampleCertの一意名で証明書を生成したと想定します
docSampleDocSamplePort stub = new docSampleDocSamplePort() stubclientCertName_x =DocSampleCert String input = これは入力文字列です String output = stubEchoString(input)
組織のサードパーティから取得した証明書を使用する従来のプロセスがありますbase64 でクライアント証明書のキーをエンコードしstub のclientCert_x変数に割り当てますプライベートキーを保護するセキュリティのベストプラクティスに従っていないためSalesforcecom 証明書を使用するより安全性が低くなりますSalesforcecom 証明書を使用する場合プライベートキーは Salesforcecom の外部に保存されません
メモ [設定] [開発] [API] [クライアント証明書の生成]で生成したクライアント証明書は使用しないでください従来のプロセスを使用する場合組織のサードパーティから取得された証明書を使用する必要があります
次の例では従来のプロセスを説明し「生成されるコードについて」 (ページ178)のサンプルWSDL ファイルを使用しています
docSampleDocSamplePort stub = new docSampleDocSamplePort() stubclientCert_x =MIIGlgIBAzCCBlAGCSqGSIb3DQEHAaCCBkEEggY9MIIGOTCCAe4GCSqGSIb3DQEHAaCCAd8EggHb+MIIB1zCCAdMGCyqGSIb3DQEMCgECoIIBgjCCAX4wKAYKKoZIhvcNAQwBAzAaBBSaUMlXnxjzpfdu+6YFwZgJFMklDWFyvCnQeuZpN2E+Rb4rf9MkJ6FsmPDA9MCEwCQYFKw4DAhoFAAQU4ZKBfaXcN45w+9hYm215CcA4n4d0EFJL8jr68wwKwFsVckbjyBzzYHO6AgIEAA==
キーストアのパスワード stubclientCertPasswd_x = passwd
String input = This is the input string String output = stubEchoString(input)
HTTP 要求での証明書の使用Salesforcecom で証明書を生成した後HTTP 要求へのコールアウトの双方向認証をサポートできます
証明書を Apex を統合する手順は次のとおりです
1 証明書を生成します証明書の一意名を入力します2 Apex でHttpRequestクラスの setClientCertificateNameメソッドを使用しますこのメソッドの引数
に使用される値は前のステップで生成された証明書の一意名に一致しなければなりません
Apex を使用したコールアウトの呼び出し Version 180 | SOAP サービスでの証明書の使用 | 183
次の例は前述の手順の最後のステップを示しますこの例ではDocSampleCertの一意名で証明書を生成したと想定します
HttpRequest req = new HttpRequest() reqsetClientCertificateName(DocSampleCert)
コールアウトの制限
Apex スクリプトでHTTP 要求または Web サービスコールに対するコールアウトを実行する場合に次の制限が適用されますWeb サービスは Forcecom Web サービス API コールの場合または外部 Web サービスコールの場合があります
bull 1 つの Apex トランザクションでHTTP 要求または API コールに対するコールアウトを最大 10 回実行できます
bull HTTP サービスまたは Web サービスのコールアウトの要求または応答の最大サイズは 1 MB ですbull デフォルトのタイムアウトが 10 秒であることカスタムタイムアウトはコールアウトごとに定義できます
最小値は 1 ミリ秒最大値は 60 秒ですWeb サービスまたは HTTP コールアウトのカスタムタイムアウトの設定方法については次の例を参照してください
bull 1 つの Apex トランザクションによる各コールアウトのタイムアウトの累積値は最大 120 秒です累積値とは特定のApexトランザクションによって呼び出されたすべてのコールアウトのタイムアウトを合計した値です
次にWeb サービスコールアウトのカスタムタイムアウトの設定についての例を示します
docSampleDocSamplePort stub = new docSampleDocSamplePort() stubtimeout_x = 2000 タイムアウト (ミリ秒)
次にHTTP コールアウトのカスタムタイムアウトの設定についての例を示します
HttpRequest req = new HttpRequest() reqsetTimeout(2000) タイムアウト (ミリ秒)
Apex を使用したコールアウトの呼び出し Version 180 | コールアウトの制限 | 184
第 12 章
参照
Apex リファレンスにはApex 言語についての情報が含まれていますトピック
bull データ操作言語 (DML) の操作 データベース内のデータの操作に使用されます
bull Apex のデータ操作言語 (DML) 操作
bull 標準クラスおよびメソッドプリミティブデータ型コレクションsObjectsApex のほかの部分に使用できます
bull Apex 標準クラスおよび標準メソッド
bull Apex クラス 使用可能な組み込みクラスbull Apex クラス
Apex のデータ操作言語 (DML) 操作
データベース内のデータを取得挿入削除更新するためにデータ操作言語 (DML)操作を使います
以下の2つの異なる形式を使ってDML操作を実行可能です
bull Apex DMLステートメントは例えば以下のものです
insert SObject[]
bull Apex DMLデータベースメソッドは例えば以下のものです
DatabaseSaveResult[] result = DatabaseInsert(SObject[])
ほとんどのDML操作がどちらの方式でも利用可能な一方でいくつかはどちらか片方にしか存在しません
異なるDML操作形式は異なるタイプの例外処理を可能にします
bull try catchブロックを使うことによって 大量のDML処理中に発生するエラーをコントロールフローを即時に遮るApex例外として出したい場合DMLを使ってくださいこの機能はほとんどのデータベースの手続き型言語における例外の処理方法に似ています
bull 大量のDML操作の部分的成功を可能にしたいならばデータベースメソッドを使ってください記録が失敗した場合もDML操作の残りは成功可能ですアプリケーションは次に記録を拒否し操作を再試行しますこの方式を使っている場合DML例外エラーを決して出さないコードを書くことができます代わりにコードは成功と失敗を判断する適切な結果列を使用可能ですDMLデータベースメソッドはDMLステートメントのように出された例外構文を含むことも可能です
以下のApex DML操作が利用可能です
bull convertLead1
bull delete
bull insert
bull merge2
bull undelete
bull update
bull upsert
システムコンテキストと共有ルール
ほとんどのDML操作はシステムコンテキストにて実行され現在のユーザのプロファイル許可フィールドレベルセキュリティ組織全体のデフォルト役割階層のポジションおよび共有ルールを無視しますしかしながらDML操作がwith sharingキーワードによって定義されたクラス内で呼び出された場合現在のユーザの共有ルールが考慮されます詳細はwith sharingまたはwithout sharingキーワードを使う (ページ 105)を参照してください
1convertLeadだけがデータベースメソッドとして利用可能です
2mergeだけがApex DMLステートメントとして利用可能です
参照 Version 180 | Apex のデータ操作言語 (DML) 操作 | 186
文字列項目の切り捨てと API バージョン
項目に割り当てた文字列値が長すぎる場合API バージョン 150 以上を使用して保存 (コンパイル) した Apex クラスにはランタイムエラーが発生します
ConvertLead 操作convertLead DML操作は 任意に 商談と同様にリードを取引先と取引先担当者に変換します
メモ convertLeadconvertLeadだけがデータベースメソッドとして利用可能です
データベースメソッド構文
bull LeadConvertResult DatabaseconvertLead(LeadConvert leadToConvert Boolean opt_allOrNone)bull LeadConvertResult[] DatabaseconvertLead(LeadConvert[] leadsToConvert Boolean opt_allOrNone)
オプションの opt_allOrNoneパラメータは一部のみの成功を許可するかどうかを指定しますこのパラメータを偽に設定した場合レコードが失敗しても残りの DML 操作を成功させることができますこのメソッドは成功したレコード失敗したレコードおよびその理由の確認に使用できる結果オブジェクトを返します
ルールとガイドライン
リードを変換する際は次のルールやガイドラインを考慮する必要があります
bull 項目マッピングシステムは標準リード項目を標準取引先取引先担当者商談項目に自動的に対応付けますカスタムリードのフィールドに関してはSalesforcecomの管理者がカスタムアカウントコンタクト商談フィールドのマッピング方法を指定することができます項目マッピングの詳細はSalesforcecom オンラインヘルプを参照してください
bull 差し込み項目 データが既存のアカウントとコンタクトオブジェクトにマージされた場合ターゲットオブジェクト内の空白のフィールドは上書きされます既存データ IDを含む は上書きされません唯一の例外はターゲットコンタクトオブジェクト内のLeadSourceフィールドがソースLeadConvertオブジェクト内のLeadSourceフィールドの内容によって上書きされる場合においてLeadConvertオブジェクトのsetOverwriteLeadSourceにTrueを指定した場合です
bull レコードタイプ組織でレコードタイプを使用している場合新しい所有者のデフォルトのレコードタイプはリード変換時に作成されたレコードに割り当てられますリードを変換するユーザのデフォルトのレコードタイプによって変換時に使用できるリードのソース値が決まります必要なリードのソース値が使用できない場合リードを変換するユーザのデフォルトのレコードタイプに値を追加しますレコードタイプの詳細はSalesforcecom オンラインヘルプを参照してください
bull 選択リスト値システムは空の標準リード選択リスト項目を対応付けるときに取引先取引先担当者商談のデフォルトの選択リストを割り当てます組織でレコードタイプを使用している場合空の値は新しいレコード所有者のデフォルトの選択リストの値で置き換えられます
bull 自動フィード登録リードを取引先取引先担当者および (オプションで) 商談に変換すると生成されたレコードの所有者が自動的に登録されリード所有者はリードレコードから登録解除されますリードに登録されたユーザは生成されたレコードに登録されリードからは登録解除されますリードに登録されたリード所有者およびその他のユーザは新規フィードで取引先取引先担当者商談のレコードの変更を確認できます[設定] [個人情報] [個人情報] の [フィードの自動登録を無効化]項目がオフであれば登録できますレコードへの変更をユーザのホームページのニュースフィードに表示できるようレコードに登録できます登録するとSalesforcecom のレコードの最新状況を確認するのに役立ちます
参照 Version 180 | ConvertLead 操作 | 187
リードの変換の基本ステップ
リードの変換は次の基本ステップに従います
1 アプリケーションがコンバートされるリードのIDを決定します2 状況に応じてアプリケーションはリードがマージされるアカウントのIDを決定しますアプリケーショ
ンはリード名にマッチするアカウントを探すためにSOQLを以下の例のように使用することができます
select id name from account where name=CompanyNameOfLeadBeingMerged
3 状況に応じてアプリケーションはそのコンタクトまたはリードがマージされるアカウントのIDを決定しますアプリケーションはリード名にマッチするコンタクトを探すためにSOQLを以下の例のように使用することができます
select id name from contact where firstName=FirstName and lastName=LastName andaccountId = 001
4 状況に応じてアプリケーションは商談がリードから作成されるかどうかを決定可能です5 すべての可能なコンバートされた状況オプションを取得するためにアプリケーションはLeadSourceテーブル
に問い合わせます(SELECT FROM LeadStatus WHERE IsConverted=1)それからコンバートされた状況の値を選択します
6 アプリケーションはconvertLeadを呼び出します7 アプリケーションは返された結果を通して繰り返され各リードにどのコンバージョンが成功したか決定
するためにに各LeadConvertResultオブジェクトを検査します8 オプションでキューが所有するリードを変換する場合は所有者を指定する必要がありますこれはキュー
が取引先と取引先担当者を所有することができないからです既存の取引先または取引先担当者を指定する場合も所有者を指定する必要があります
LeadConvertオブジェクトメソッド
convertLeadデータベースメソッドは最高で100のLeadConvertオブジェクトをを受け付けますLeadConvertオブジェクトは以下のメソッドをサポートします
説明戻り値の型引数名前
リードのマージ先アカウントのIDを設定しますIDgetAccountId
リードのマージ先取引先担当者のIDを設定しますIDgetContactId
コンバートされたリードのリードステータス値を取得します
StringgetConvertedStatus
変換するリードのIDを取得しますIDgetLeadID
作成する商談名を取得しますStringgetOpportunityName
新しく作成する取引先取引先担当者商談の所有者となるユーザの ID を取得します
IDgetOwnerID
リード変換時に商談を作成するかどうかを指定 (デフォルトの falseで商談を作成しtrueでは作成しない)します
BooleanisDoNotCreateOpportunity
参照 Version 180 | ConvertLead 操作 | 188
説明戻り値の型引数名前
ターゲットの取引先担当者オブジェクトの LeadSource
項目にソースのリードオブジェクトのLeadSource項BooleanisOverWriteLeadSource
目の値を上書きするかどうかを指定します (上書きする場合は true上書きしない場合は falseでデフォルトでは上書きしません)
setOwnerIdで指定された所有者に電子メールの通知を送るかどうかを指定 (送る場合はtrue送らない場合はfalseでデフォルトでは送らない) します
BooleanisSendNotificationEmail
リードのマージ先アカウントのIDを設定します既存アカウント 個人取引先を含む が更新される時のみこの値
VoidID IDsetAccountId
は要求されます該当しない場合はsetAccountIDが指定された場合新しいアカウントが作成されます
リードのマージ先コンタクトのIDを設定します このコンタクトはsetAccountIdで指定されたアカウントに
VoidID IDsetContactId
関連づれられている必要がありますsetAccountIdは指定される必要があります 既存コンタクトを更新する場合のみこの値が必要です
重要 リードをパーソナルアカウントにコンバートする場合setContactIdを指定しないでください指定するとエラーが発生します個人取引先のsetAccountIdのみ指定してください
setContactIDが指定された場合アプリケーションはアカウントに暗黙的に関連付けられた新しいコンタクトを作成しますコンタクト名とその他の既存データは上書きされません LeadSourceフィールドのみが上書きされる設定であるsetOverwriteLeadSourceがTrueに設定されていない限り
コンバートされたリードのリードステータス値を設定しますこのフィールドは必要です
VoidString StatussetConvertedStatus
リードコンバージョン中に商談を作成するかどうか指定しますデフォルト値はfalseですデフォルトで商談
VoidBooleanCreateOpportunity
setDoNotCreateOpportunity
は作成されますリードの商談を作成したくない場合のみこのフラグを trueに設定します
コンバートするリードのIDを設定してくださいこのフィールドは必要です
VoidID IDsetLeadId
作成する商談名を設定してください名前が指定されない場合この値の規定値はリードの会社名になりま
VoidString OppNamesetOpportunityName
すこの項目の文字数は 80 文字までですsetDoNotCreateOpportunityがTrueの場合商談は作成されずこのフィールドは空白のまま残されますそうでない場合はエラーが返されます
参照 Version 180 | ConvertLead 操作 | 189
説明戻り値の型引数名前
ターゲットコンタクトオブジェクト上のLeadSource
フィールドをソースリードオブジェクト内のLeadSource
VoidBooleanOverwriteLeadSource
setOverwriteLeadSource
フィールドの内容で上書きするかどうかを指定する規定値はFalseでそのフィールドを上書きしませんTrueとして指定した場合はターゲットコンタクト用のsetContactIdも指定する必要があります
新しく作成する取引先取引先担当者商談の所有者となるユーザの ID を指定アプリケーションがこの値を
VoidID IDsetOwnerId
指定しない場合は新規オブジェクトのオーナーはリードのオーナーになりますこのメソッドは既存オブジェクトをマージするのには適用不可ですsetOwnerIdが指定された場合ownerIdフィールドは既存アカウントまたはコンタクト内で上書きされません
setOwnerIdによって指定されたオーナーに通知電子メールを送信するか指定します規定値はFalseで送信しません
VoidBooleanSendEmail
setSendNotificationEmail
LeadConvertResultオブジェクト
LeadConvertResultオブジェクトの列はconvertLeadデータベースメソッドで返されますSObject列に関連したLeadConvertResult列内の各エレメントはconvertLeadデータベースメソッド内の SObject[]パラメータとして通過しますつまりLeadConvertResult列内の最初のエレメントはSObject列内の最初のエレメントにマッチしますまた二番目のエレメントは2 番目のエレメントに対応し3 番目以降も同じです1つしかsObjectが渡されない場合LeadConvertResults 列は1つのエレメントしか含みません
LeadConvertResultオブジェクトは以下のメソッドを持っています
説明型名前
新規アカウントのID(新規アカウントが指定されている場合)またはconvertLeadが呼び出された時に指定されたアカウントのID
IDgetAccountId
新規コンタクトのID(新規コンタクトが指定されている場合)またはconvertLeadが呼び出された時に指定されたコンタクトのID
IDgetContactId
エラーが発生した場合エラーコードと説明を提供している1つ以上のデータベースエラーオブジェクト詳細
DatabaseError[]DatabaseError []
getErrors
は「データベースエラーオブジェクトメソッド」(ページ 277)を参照してください
コンバートされたリードのIDIDgetLeadId
新規商談のIDconvertLead呼び起こされた際に作成された場合
IDgetOpportunityId
参照 Version 180 | ConvertLead 操作 | 190
説明型名前
DML操作がこのオブジェクトに対して成功した場合TrueのBoolean値となるそうでない場合Falseとなる
BooleanisSuccess
データベースメソッド例
Lead myLead = new Lead(lastname = Fry company=Fry And Sons) insert myLead
DatabaseLeadConvert lc = new databaseLeadConvert() lcsetLeadId(myLeadid)
LeadStatus convertStatus = [Select Id MasterLabel from LeadStatus where IsConverted=truelimit 1] lcsetConvertedStatus(convertStatusMasterLabel)
DatabaseLeadConvertResult lcr = DatabaseconvertLead(lc) Systemassert(lcrisSuccess())
Delete 操作delete DML 操作は1つ以上の既存の sObject レコード個別アカウントまたはコンタクトなどをあなたの組織のデータベースから削除します deleteはForcecom Web サービス API 内の delete()ステートメントに似ています
DMLステートメント構文delete sObject | RecordID
データベースメソッド構文
bull DeleteResult DatabaseDelete((sObject recordToDelete | RecordID ID) Boolean opt_allOrNone)bull DeleteResult[]DatabaseDelete((sObject[] recordsToDelete | RecordIDs LISTIDs) Boolean opt_allOrNone)
オプションの opt_allOrNoneパラメータは一部のみの成功を許可するかどうかを指定しますこのパラメータを偽に設定した場合レコードが失敗しても残りの DML 操作を成功させることができますこのメソッドは成功したレコード失敗したレコードおよびその理由の確認に使用できる結果オブジェクトを返します
ルールとガイドライン
sObjectレコードを削除する際は以下のルールとガイドラインを考慮してください
bull 参照の完全性を確実にするためにdeleteはカスケーディング削除をサポートします親オブジェクトを削除した場合各子レコードが削除可能な場合自動的に子オブジェクトも削除されます
例えばケースレコードを削除した場合Apexは自動的にそのケースに関連したCaseCommentCaseHistoryおよびCaseSolutionレコードを削除しますしかしながら特定の子レコードは削除不可能か現在使用中の場合親ケースレコード上のdelete操作は失敗します
bull 特定のsObjectsは削除不可能ですあるsObjectレコードを削除するにはsObjectのdeletableプロパティをTrueに設定しておく必要がありますsObjects That Do Not Support DML Operations (ページ 204)も参照してください
bull 最大1000のsObjectレコードを単一のdeleteメソッドに渡すことができます
参照 Version 180 | Delete 操作 | 191
DeleteResult オブジェクト
DatabaseDeleteResult オブジェクトの配列はdeleteデータベースメソッドで返されますSObject 列に関連した DeleteResult 列内の各エレメントはdeleteデータベースメソッドの sObject[]パラメータの列と一致しますつまりDeleteResult 列内の最初のエレメントはsObject 列内の最初のエレメントにマッチしますまた 2番目のエレメントは2 番目のエレメントに対応し 3 番目以降も同じです1つしかsObjectが渡されない場合DeleteResults列は1つのエレメントしか含みません
DatabaseDeleteResult オブジェクトには次のメソッドがあります
説明型名前
エラーが発生した場合エラーコードと説明を提供している1つ以上のデータベースエラーオブジェクト詳細は
DatabaseError[]getErrors
「データベースエラーオブジェクトメソッド」 (ページ277)を参照してください
削除しようとしているsObjectのIDこのフィールドがある値を含む場合オブジェクトの削除は成功しています
IDgetId
このフィールドが空白の場合はその操作はそのオブジェクトに対して成功していません
DML操作がこのオブジェクトに対して成功した場合TrueのBoolean値となるそうでない場合Falseとなる
BooleanisSuccess
DMLステートメント例
以下の例は「DotCom」と名づけられたアカウントの消去を示しています
Account[] doomedAccts = [select id name from account where name = DotCom] try deletedoomedAccts catch (DmlException e) Process exception here
メモ 処理DmlExceptionに関する詳細はBulk DML Exception Handling (ページ 205)を参照してください
データベースメソッド例
以下の例は「DotCom」と名づけられたアカウントの消去を示しています
public class DmlTest Account[] doomedAccts = [select id name from account where name =DotCom] DatabaseDeleteResult[] DR_Dels = Databasedelete(doomedAccts)
Insert 操作insert DML 操作は個別アカウントまたはコンタクトなどの1つ以上のsObjectをあなたの組織のデータに追加しますinsertはSQL の INSERT ステートメントを似ています
DMLステートメント構文insert sObject
参照 Version 180 | Insert 操作 | 192
insert sObject[]
データベースメソッド構文
bull SaveResult Databaseinsert(sObject recordToInsert Boolean opt_allOrNone | databaseDMLOptionsopt_DMLOptions)
bull SaveResult[] Databaseinsert(sObject[] recordsToInsert Boolean opt_allOrNone | databaseDMLOptionsopt_DMLOptions)
オプションの opt_allOrNoneパラメータは一部のみの成功を許可するかどうかを指定しますこのパラメータを偽に設定した場合レコードが失敗しても残りの DML 操作を成功させることができますこのメソッドは成功したレコード失敗したレコードおよびその理由の確認に使用できる結果オブジェクトを返します
例
DatabaseSaveResult[] MySaveResult = DatabaseInsert(MyAccounts false)
オプションのopt_DMLOptionsパラメータは割り当てルール情報または切り捨ての動作などトランザクションの追加データを指定します
例
AssignmentRuleHeader UseDefaultRule databaseDMLOptions dmo = new databaseDMLOptions()dmoAssignmentRuleHeaderUseDefaultRule= true
Lead l = new Lead(company=ABC lastname=Smith) lsetOptions(dmo)
insert l
詳細はデータベース DMLOptions メソッド (ページ 273)を参照してください
ルールとガイドライン
sObjectレコードを挿入する際は以下のルールとガイドラインを考慮してください
bull 特定のsObjectsは挿入不可能ですあるsObjectレコードを作成するにはsObjectのcreateableプロパティをTrueに設定しておく必要があります
bull すべての必要フィールドにnullではない値を入力する必要がありますbull 最大1000のsObjectレコードを単一のinsertメソッドに渡すことができますbull insertステートメントはすべての新規sObjectレコードのID値を自動的に設定しますすでにIDを持ってい
る すなわちすでに組織のデータ内に存在している レコードの挿入はエラーを発生させます詳細については「リスト (ページ 34)」 を参照してください
bull insertステートメントのみが関連sObjectレコードの外部キーIDを設定可能です関連レコードのフィールドはinsertでは更新できません例えば新規コンタクトを挿入した場合AccountIdフィールドの値を設定することによってコンタクトの関連アカウントレコードを指定可能ですしかしながらアカウント自体を更新せずに別のDMLコールを使ってアカウント名を変更することはできません
bull insertステートメントはいつくかのsObjectではサポートされませんDML操作をサポートしないsObject(ページ 204)を参照してください
bull この操作は重複ID値に関してレコードの各かたまりをチェックします重複がある場合は最初の 5 つが処理されます6番目とすべての追加重複IDについてはそのエントリ用のSaveResultが以下に類似したエラーによってマークされますMaximum number of duplicate updates in one batch (5allowed)Attempt to update Id more than once in this API call number_of_attempts
参照 Version 180 | Insert 操作 | 193
SaveResultオブジェクト
SaveResultオブジェクトの列はinsertとupdateのデータベースメソッドで返されますSObject列に関連したSaveResult列内の各エレメントはデータベースメソッド内のsObject[]パラメータの列と一致しますすなわちSaveResult列内の最初のエレメントはsObject列内の最初のエレメントにマッチしますまた二番目のエレメントは二番目のエレメントに対応し三番目以降も同じです1つしかsObjectが渡されない場合 SaveResults列は1つのエレメントしか含みません
SaveResultオブジェクトは以下のメソッドを持っています
説明型名前
エラーが発生した場合エラーコードと説明を提供している1つ以上の
DatabaseError[]getErrors
データベースエラーオブジェクト詳細は「データベースエラーオブジェクトメソッド」 (ページ277)を参照してください
挿入または更新しようとしているsObjectのIDこのフィールドがある値
IDgetId
を含む場合オブジェクトの挿入または更新は成功していますこのフィールドが空白の場合はその操作はそのオブジェクトに対して成功していません
DML操作がこのオブジェクトに対して成功した場合Trueに設定されたBooleanそうでない場合False
BooleanisSuccess
DMLステートメント例
以下の例は「Acme」と名づけられたアカウントの挿入を示しています
Account newAcct = new Account(name = Acme) try insert newAcct catch (DmlExceptione) Process exception here
メモ 処理DmlExceptionに関する詳細はBulk DML Exception Handling (ページ 205)を参照してください
データベースメソッド例
以下の例は「Acme」と名づけられたアカウントの挿入を示しています
Account a = new Account(name = Acme) DatabaseSaveResult[] lsr = Databaseinsert(newAccount[]a new Account(name = Acme) false)
Iterate through the Save Results for(DatabaseSaveResult srlsr) if(srisSuccess())DatabaseError err = srgetErrors()[0]
参照 Version 180 | Insert 操作 | 194
Merge ステートメントmergeステートメントは同じsObjectタイプの最大3つのレコードをレコードの1つにマージしその他を削除し関連レコードを再ペアレント化します
メモ このDML操作はマッチングデータベースシステムメソッドを持っていません
構文merge sObject sObject
merge sObject sObject[]
merge sObject ID
merge sObject ID[]
最初のパラメータは他のレコードのマージ先のマスターレコードを表します二番目のパラメータはマージされてから削除される1つまたは2つの他のレコードを表しますこれらの他のレコードを単一のsObjectレコードまたはIDとしてもしくは2つのsObjectレコードまたはIDとしてmergeステートメントにパスすることができます
ルールとガイドライン
sObjectレコードをマージする際は以下のルールとガイドラインを考慮してください
bull リード コンタクトおよびアカウントだけがマージ可能ですDML操作をサポートしないsObject (ページ204)を参照してください
bull マスターレコードと最大2つのsObjectを1つのmergeメソッドにパスすることができます
リード取引先取引先担当者の結合の詳細はSalesforcecom オンラインヘルプを参照してください
例
以下の例は2つの「Acme Inc」と「Acme」と名づけられたアカウントを1つのレコードにマージします
ListltAccountgt ls = new ListltAccountgtnew Account(name=Acme Inc)new Account(name=Acme)insert ls Account masterAcct = [select id name from account where name = Acme Inclimit 1] Account mergeAcct = [select id name from account where name = Acme limit 1]try merge masterAcct mergeAcct catch (DmlException e) Process exception here
メモ DmlExceptionの処理に関する詳細は「大量DML例外処理 (ページ 205)」を参照してください
Undelete 操作undeleteDML操作は個別アカウントまたはコンタクトなどの1つ以上のsObjectをあなたの組織のごみ箱から復元させますundeleteはSQLのUNDELETEステートメントを似ています
DMLステートメント構文undelete sObject | RecordID
参照 Version 180 | Merge ステートメント | 195
undelete sObject[] | LISTID[]
データベースメソッド構文
bull UndeleteResult DatabaseUndelete((sObject recordToUndelete | RecordID ID) Boolean opt_allOrNone)bull UndeleteResult[] DatabaseUndelete((sObject[] recordsToUndelete | RecordIDs LISTIDs) Boolean
opt_allOrNone)
オプションの opt_allOrNoneパラメータは一部のみの成功を許可するかどうかを指定しますこのパラメータを偽に設定した場合レコードが失敗しても残りの DML 操作を成功させることができますこのメソッドは成功したレコード失敗したレコードおよびその理由の確認に使用できる結果オブジェクトを返します
ルールとガイドライン
sObjectレコードを復元する際は以下のルールとガイドラインを考慮してください
bull 参照の完全性を確実にするためにundeleteは以下のタイプの関連性に関するレコード関連付けを復元させます
- 親取引先 (取引先の [親取引先]項目で指定)- 親ケース (ケースの [親ケース]項目で指定)- 翻訳ソリューションのマスタソリューション (ソリューションの [マスタソリューション]項目で指定)- 取引先責任者のマネージャ (取引先責任者の [上司]項目で指定)- 納入商品に関連付けられている商品 (納入商品の [商品]項目で指定)- 見積に関連付けられている商談 (見積の [商談]項目で指定)- すべてのカスタム参照関係- 取引先およびリレーショングループのリレーショングループメンバー (一部例外あり)- タグ- 記事のカテゴリ公開の状況および割り当てSalesforcecomオンラインヘルプの「記事の管理」を参照
してください
メモ Salesforcecom は置換されていない参照関係のみを復元しますたとえば納入商品が元の商品レコードが元に戻される前に別の商品と関連付けられている場合その納入商品と商品のリレーションは復元されません
bull 特定のsObjectsは復元不可能ですあるsObjectが復元不可能かどうか確認するためにはsObjectのundeletable
プロパティがTrueに設定されているか確認してくださいbull 最大1000のsObjectレコードを単一のundeleteメソッドに渡すことができますbull 結合の結果として削除されたレコードを復元できますが子オブジェクトは再ペアレント化されやり直す
ことはできませんbull マージの結果削除されたレコード含むレコードを削除するにはSOQL問い合わせundeleteを使ってくださ
いステートメントですべてのレコードを問い合わせる (ページ 60)を参照してくださいbull いくつかのsObjectでは復元はサポートされていませんDML操作をサポートしないsObject (ページ 204)を
参照してください
UndeleteResultオブジェクト
DatabaseUndeleteResult オブジェクトの配列はundeleteデータベースメソッドで返されますSObject 列に関連した UndeleteResult 列内の各エレメントはundeleteデータベースメソッドの sObject[]パラメータの列と
参照 Version 180 | Undelete 操作 | 196
一致しますつまりUndeleteResult 列内の最初のエレメントはsObject 列内の最初のエレメントにマッチしますまた 2 番目のエレメントは2 番目のエレメントに対応し3 番目以降も同じです1つしかsObjectがパスされない場合UndeleteResult列は1つのエレメントしか含みません
undeleteResultオブジェクトは以下のメソッドを持っています
説明型名前
エラーが発生した場合エラーコードと説明を提供している1つ以上の
DatabaseError[]getErrors
データベースエラーオブジェクト詳細は「データベースエラーオブジェクトメソッド」 (ページ277)を参照してください
復元しようとしているsObjectのIDこのフィールドがある値を含む場合
IDgetId
オブジェクトの復元は成功していますこのフィールドが空白の場合はその操作はそのオブジェクトに対して成功していません
DML操作がこのオブジェクトに対して成功した場合TrueのBoolean値となるそうでない場合Falseとなる
BooleanisSuccess
DMLステートメント例
以下の例は「Trump」と名づけられたアカウントの復元を示していますALL ROWSキーワードは削除されたレコードとアーカイブされたアクテビティを含むトップレベルと総関係の両方の全ての列を問い合わせます
Account a = new Account(name=AC1) insert(a) insert(newContact(lastName=CarteraccountId=aid))
Account[] savedAccts = [select id name from account where name = Trump ALL ROWS] try undelete savedAccts catch (DmlException e) Process exception here
メモ DmlExceptionの処理に関する詳細は「大量DML例外処理 (ページ 205)」を参照してください
データベースメソッド例
以下の例は「Trump」と名づけられたアカウントの復元を示していますALL ROWSキーワードは削除されたレコードとアーカイブされたアクテビティを含むトップレベルと総関係の両方の全ての列を問い合わせます
public class DmlTest2
public void undeleteExample() Account[] SavedAccts = [select id name from account wherename = Trump ALL ROWS] DatabaseUndeleteResult[] UDR_Dels = Databaseundelete(SavedAccts)for(integer i =0 ilt 10 i++) if(UDR_Dels[i]getErrors()size()gt0) Process any errorshere
参照 Version 180 | Undelete 操作 | 197
Update 操作updateDML操作は個別アカウントまたはコンタクトなどの1つ以上の既存sObjectをあなたの組織のデータを修正します updateはSQLのUPDATEステートメントを似ています
DMLステートメント構文update sObject
update sObject[]
データベースメソッド構文
bull UpdateResult Update(sObject recordToUpdate Boolean opt_allOrNone | databaseDMLOptions opt_DMLOptions)bull UpdateResult[] Update(sObject[] recordsToUpdate[] Boolean opt_allOrNone | databaseDMLOptions
opt_DMLOptions)
オプションの opt_allOrNoneパラメータは一部のみの成功を許可するかどうかを指定しますこのパラメータを偽に設定した場合レコードが失敗しても残りの DML 操作を成功させることができますこのメソッドは成功したレコード失敗したレコードおよびその理由の確認に使用できる結果オブジェクトを返します
オプションのopt_DMLOptionsパラメータは割り当てルール情報または切り捨ての動作などトランザクションの追加データを指定します
詳細はデータベース DMLOptions メソッド (ページ 273)を参照してください
ルールとガイドライン
sObjectレコードを更新する際は以下のルールとガイドラインを考慮してください
bull 特定のsObjectsは更新不可能ですあるsObjectレコードを更新するにはsObjectのupdateableプロパティをTrueに設定しておく必要があります
bull 必要なフィールドを更新する際はnullではない値を入力する必要がありますbull Forcecom Web Services APIの場合とは違ってApexはsObjectレコード上のfieldsToNull列を更新せずに
フィールド値をnullにすることが可能です多くのSOAPプロバイダによるnull値の一貫性のない処理が行われたためAPI はこの列の更新を要求しますApexはForcecomプラットフォーム上だけで実行されるのでこの回避方法は不要です
bull 更新されたsObjectレコードのIDは修正不可能ですが関連レコードIDは修正可能ですbull この操作は重複ID値に関してレコードの各かたまりをチェックします重複がある場合は最初の 5 つ
が処理されます6番目とすべての追加重複IDについてはそのエントリ用のSaveResultが以下に類似したエラーによってマークされますMaximum number of duplicate updates in one batch (5allowed)Attempt to update Id more than once in this API call number_of_attempts
bull updateステートメントはLastModifiedDateLastModifiedByIdSystemModstampなどの特定のフィールドを自動的に修正しますApexスクリプトにてこれらの値を明示的に指定することはできません
bull 最大1000のsObjectレコードを単一のupdateメソッドに渡すことができますbull 単一のupdateステートメントは一度にたった1つのタイプのsObjectしか修正できません例えば修正さ
れたことのある既存コンタクトを通してアカウントフィールドを更新する場合以下の2つのupdateステートメントが必要です
Use a SOQL query to access data for a contact Contact c = [select accountname fromcontact where lastName = Carter limit 1]
参照 Version 180 | Update 操作 | 198
Now we can change fields for both the contact and its associated accountcaccountname = salesforcecom clastName = Roth
データベースを更新するには2 種類のレコードを 個別に更新する必要があります update c 連絡先の名前のみ変更します update caccount 取引先名を更新します
bull いくつかのsObjectでは更新はサポートされていませんDML操作をサポートしないsObject (ページ 204)を参照してください
SaveResultオブジェクト
SaveResultオブジェクトの列はinsertとupdateのデータベースメソッドで返されますSObject列に関連したSaveResult列内の各エレメントはデータベースメソッド内のsObject[]パラメータの列と一致しますすなわちSaveResult列内の最初のエレメントはsObject列内の最初のエレメントにマッチしますまた二番目のエレメントは二番目のエレメントに対応し三番目以降も同じです1つしかsObjectが渡されない場合 SaveResults列は1つのエレメントしか含みません
SaveResultオブジェクトは以下のメソッドを持っています
説明型名前
エラーが発生した場合エラーコードと説明を提供している1つ以上の
DatabaseError[]getErrors
データベースエラーオブジェクト詳細は「データベースエラーオブジェクトメソッド」 (ページ277)を参照してください
挿入または更新しようとしているsObjectのIDこのフィールドがある値
IDgetId
を含む場合オブジェクトの挿入または更新は成功していますこのフィールドが空白の場合はその操作はそのオブジェクトに対して成功していません
DML操作がこのオブジェクトに対して成功した場合Trueに設定されたBooleanそうでない場合False
BooleanisSuccess
DMLステートメント例
以下の例は「Acme」と名づけられた1つのアカウント上のbillingcityフィールドを更新します
Account a = new Account(name=Acme2) insert(a)
Account myAcct = [select id name billingcity from account where name = Acme2 limit 1]myAcctbillingcity = San Francisco try update myAcct catch (DmlException e) Process exception here
メモ DmlExceptionの処理に関する詳細は「大量DML例外処理 (ページ 205)」を参照してください
参照 Version 180 | Update 操作 | 199
データベースメソッド例
以下の例は「Acme」と名づけられた1つのアカウント上のbillingcityフィールドを更新します
Account myAcct = [select id name billingcity from account limit 1] myAcctbillingcity =San Francisco
DatabaseSaveResult SR = databaseupdate(myAcct) for(DatabaseError err SRgetErrors()) process any errors here
Upsert操作upsertDML操作は既存オブジェクトの存在を決定する任意のカスタムフィールドを使って1つのステートメント内で新規sObjectレコードを作成し既存のsObjectレコードを更新します
DMLステートメント構文upsert sObject opt_external_id
upsert sObject[] opt_external_id
opt_external_idは組織のデータ内にすでに存在しているレコードにマッチするために使われるカスタムフィールドを指定する任意の変数ですカスタムフィールドは選択されたExternal Id属性で作成される必要がありますさらに項目に選択された Unique属性がない場合upsertが誤って重複レコードを挿入しないようにコンテキストユーザ「すべてを参照」オブジェクトレベルの権限か「すべてのデータを参照」権限が必要です
opt_external_idが指定されていない場合sObjectレコードのIDフィールドは規定値で使われます
メモ カスタムフィールドがフィールド定義の一部として「一意」と「ABC と abc を重複した値として扱う (大文字小文字の区別なし)」属性を選択している場合のみカスタムフィールドは大文字と小文字を区別しませんこの場合「ABC123」は「abc123」と一致します詳細はSalesforcecom オンラインヘルプの「項目とリレーションの追加」を参照してください
データベースメソッド構文
bull UpsertResult DatabaseUpsert(sObject recordToUpsert SchemaSObjectField External_ID_Field Booleanopt_allOrNone)
bull UpsertResult[] DatabaseUpsert(sObject[] recordsToUpsert SchemaSObjectField External_ID_Field Booleanopt_allOrNone)
External_ID_Fieldパラメータは組織のデータ内にすでに存在しているレコードにマッチするために使われるカスタムフィールドを指定する任意の変数ですカスタムフィールドは選択されたExternal Id属性で作成される必要がありますさらに項目に選択された Unique属性がない場合upsertが誤って重複レコードを挿入しないようにコンテキストユーザ「すべてを参照」オブジェクトレベルの権限か「すべてのデータを参照」権限が必要です
External_ID_Fieldは SchemaSObjectFieldつまり項目トークンですfields特殊メソッドを使用して項目のトークンを検索しますたとえばSchemaSObjectField f = AccountFieldsMyExternalIdとなります
External_ID_Fieldが指定されていない場合sObjectレコードのIDフィールドは規定値で使われます
参照 Version 180 | Upsert操作 | 200
メモ カスタムフィールドがフィールド定義の一部として「一意」と「ABC と abc を重複した値として扱う (大文字小文字の区別なし)」属性を選択している場合のみカスタムフィールドは大文字と小文字を区別しませんこの場合「ABC123」は「abc123」と一致します詳細はSalesforcecom オンラインヘルプの「項目とリレーションの追加」を参照してください
オプションの opt_allOrNoneパラメータは一部のみの成功を許可するかどうかを指定しますこのパラメータを偽に設定した場合レコードが失敗しても残りの DML 操作を成功させることができますこのメソッドは成功したレコード失敗したレコードおよびその理由の確認に使用できる結果オブジェクトを返します
Upsertが挿入または更新を選ぶ方法
Upsertは新規オブジェクトレコードを作成するか既存のものを更新するか決定するためにsObjectのレコードのプライマリキー または指定されている場合外部ID を使います
bull キーがマッチしない場合新規オブジェクトのレコードは作成されませんbull キーがマッチする場合既存オブジェクトのレコードが更新されますbull キーが複数回マッチする場合はエラーが生成されオブジェクトレコードは挿入も更新もされません
ルールとガイドライン
sObjectレコードを upsert する際は以下のルールとガイドラインを考慮してください
bull 特定のsObjectsは挿入も更新も不可能ですあるsObjectレコードを挿入するにはsObjectのcreateableプロパティをTrueに設定しておく必要がありますあるsObjectレコードを更新するにはsObjectのupdateable
プロパティをTrueに設定しておく必要がありますbull レコードが挿入されるすべての必要フィールドにnullでない値を入力する必要がありますbull sObjectレコードのIDは修正不可能ですが関連レコードIDは修正可能ですこのアクションは更新とし
て解釈されますbull upsertステートメントはLastModifiedDateLastModifiedByIdSystemModstampなどの特定のフィー
ルドを自動的に修正しますApexスクリプトにてこれらの値を明示的に指定することはできませんbull 各upsertステートメントは2つの操作から成ります1つはレコードの挿入で1つはレコードの更新で
すこれらの各操作はinsertとupdateのランタイムリミットにそれぞれ制限されます例えば200を超えるレコードをupsertする場合ですべてが更新中の場合エラーが発生します 実行ガバナと制限を理解するを参照してください
bull upsertステートメントのみが関連sObjectレコードのIDを設定可能です関連レコードのフィールドはupsertでは修正できません例えば既存コンタクトを更新する場合AccountIdフィールドの値を設定することによってコンタクトの関連アカウントレコードを指定可能ですしかしながらアカウント自体を更新せずに別のDMLステートメントを使ってアカウント名を変更することはできません
bull いくつかのsObjectではUpsertはサポートされていませんDML操作をサポートしないsObject (ページ204)を参照してください
bull 参照フィールドとして設定されている場合sObjectレコードをupsertするために外部キーを使用可能です詳細はForcecom Web Services API Developers Guide内のhttpwwwsalesforcecomusdeveloperdocsapiindex_CSHhtmfield_typeshtmを参照してください
UpsertResultオブジェクト
DatabaseUpsertResult オブジェクトの配列はupsertデータベースメソッドで返されますSObject列に関連したUpsertResult列内の各エレメントはupsertデータベースメソッドの sObject[]パラメータの列と一致しますつまりUpsertResult列内の最初のエレメントはsObject列内の最初のエレメントにマッチしますまた 2
参照 Version 180 | Upsert操作 | 201
番目のエレメントは2 番目のエレメントに対応し3 番目以降も同じです1つしかsObjectがパスされない場合UpsertResult列は1つのエレメントしか含みません
UpsertResultオブジェクトは以下のメソッドを持っています
説明型名前
エラーが発生した場合エラーコードと説明を提供している1つ以上の
DatabaseError[]getErrors
データベースエラーオブジェクト詳細は「データベースエラーオブジェクトメソッド」 (ページ277)を参照してください
更新または挿入しようとしているsObjectのIDこのフィールドがある値
IDgetId
を含む場合オブジェクトの更新または挿入は成功していますこのフィールドが空白の場合はその操作はそのオブジェクトに対して成功していません
レコードが作成された場合Trueに設定されたBoolean値レコードが更新された場合False
BooleanisCreated
DML操作がこのオブジェクトに対して成功した場合TrueのBoolean値となるそうでない場合Falseとなる
BooleanisSuccess
DMLステートメント例
以下の例は更新します以前Bombayとして知られていた都市の中に位置するすべての既存アカウント用に都市名を更新しSan Franciscoに位置する新規アカウントを挿入します
Account[] acctsList = [select id name billingcity from account where billingcity =Bombay] for (Account a acctsList) abillingcity = Mumbai Account newAcct = newAccount(name = Acme billingcity = San Francisco) acctsListadd(newAcct) try upsertacctsList catch (DmlException e) Process exception here
メモ DmlExceptionの処理に関する詳細は「大量DML例外処理 (ページ 205)」を参照してください
この次の例はアセットと商談ラインアイテムの一対一の関係を保持するためにupsertとAssetオブジェクト上の外部IDフィールド Line_Item_Id__cを使いますupsertを外部IDと一緒に使うことはコード内のDMLステートメントの数を減らしガバナリミットに当たること防ぐことに役立ちます(実行ガバナとリミットを理解するを参照)
参照 Version 180 | Upsert操作 | 202
メモ この例ではLine_Item_Id__cと名づけられたAssetオブジェクト上のカスタムテキストフィールドの追加が必要ですこのフィールドは外部IDとしてフラグ付けされる必要がありますカスタムフィールドに関する詳細はSalesforcecom オンラインヘルプをご覧ください
public void upsertExample() Opportunity opp = [Select Id Name AccountId (Select IdPricebookEntryProduct2Id PricebookEntryName From OpportunityLineItems) From OpportunityWhere HasOpportunityLineItem = true Limit 1]
Asset[] assets = new Asset[]
Create an asset for each line item on the opportunity for (OpportunityLineItemlineItemoppOpportunityLineItems)
This code populates the line item Id AccountId and Product2Id for each asset Asset asset= new Asset(Name = lineItemPricebookEntryName Line_Item_ID__c = lineItemId AccountId= oppAccountId Product2Id = lineItemPricebookEntryProduct2Id)
assetsadd(asset)
try upsert assets Line_Item_ID__c This line upserts the assets list with theLine_Item_Id__c field specified as the Asset field that should be used for matching the record that should be upserted catch (DmlException e) Systemdebug(egetMessage())
DMLステートメント例
以下はデータベースupsertメソッドを使った例です
This class demonstrates and tests the use of the partial processing DML operations
public class dmlSamples
This method accepts a collection of lead records and creates a task for the owner(s) ofany leads that were created as new that is not updated as a result of the upsert operation public static ListltDatabaseupsertResultgt upsertLeads(ListltLeadgt leads)
Perform the upsertIn this case the unique identifier for the insert or update decisionis the Salesforce record ID If the record ID is null the row will be inserted otherwisean update will be attempted ListltDatabaseupsertResultgt uResults =Databaseupsert(leadsfalse)
This is the list for new tasks that will be inserted when new leads are createdListltTaskgt tasks = new ListltTaskgt() for(DatabaseupsertResult resultuResults) if(resultisSuccess() ampamp resultisCreated()) tasksadd(new Task(subject = Follow-up whoId= resultgetId()))
If there are tasks to be inserted insert them Databaseinsert(tasks)
return uResults
public static testMethod void testUpsertLeads() We only need to test the insert sideof upsert ListltLeadgt leads = new ListltLeadgt()
Create a set of leads for testing for(Integer i = 0i lt 100 i++) leadsadd(newLead(lastName = testLead company = testCompany))
Switch to the runtime limit context TeststartTest()
Exercise the method ListltDatabaseupsertResultgt results = DmlSamplesupsertLeads(leads)
Switch back to the test context for limits TeststopTest()
ID set for asserting the tasks were created as expected SetltIdgt ids = new SetltIdgt()
参照 Version 180 | Upsert操作 | 203
Iterate over the results asserting success and adding the new ID to the set for use inthe comprehensive assertion phase below for(DatabaseupsertResult resultresults) Systemassert(resultisSuccess()) idsadd(resultgetId())
Assert that exactly one task exists for each lead that was inserted for(Lead l[selectid (select subject from Tasks) from lead where Id in ids]) SystemassertEquals(1ltaskssize())
DML 操作をサポートしない sObjects
DML操作はApex内の以下のsObjectではサポートされません
bull AccountTerritoryAssignmentRulebull AccountTerritoryAssignmentRuleItembull ApexComponentbull ApexPagebull BusinessHoursbull BusinessProcessbull CategoryNodebull CurrencyTypebull DatedConversionRatebull ProcessInstancebull プロファイルbull RecordTypebull SelfServiceUserbull StaticResourcebull UserAccountTeamMemberbull UserTerritorybull WebLink
Forcecom Web Services API内のこれらのsObjectを作成更新または削除することはできません
DML 操作内で一緒に使用できない sObject
一部の SObject はDML 操作をトランザクションごとに1つのタイプでのみ実行する必要がありますたとえば取引先の挿入ユーザグループグループメンバの挿入は1つのトランザクション内ではできません次の sObjects を 1 つのトランザクション内で同時に使用することはできません
bull Group3
bull GroupMemberbull QueueSObjectbull User4
bull UserRole
3 他の sObjects とともに 1 つのトランザクション内でグループを挿入および更新できます他の DML 操作は使用できません
4roleidが Null として指定されている場合他の sObjects とトランザクション内でユーザを挿入できます
参照 Version 180 | DML 操作をサポートしない sObjects | 204
bull UserTerritorybull テリトリー
重要 主な例外はテスト内でrunAsメソッドを使用している場合です詳細は「システムメソッド」(ページ 285)を参照してください
以下のプロセスを使って1つのクラスで複数タイプのsObjectにおいてDML操作を実行することができます
1 1つのタイプのsObjectにおいてあるDML操作を行うメソッドを作成してください2 二番目のsObjectタイプを操るためのfutureアノテーションを使う二番目のメソッドを作成してください
カスタムコントローラでVisualforceページを使っている場合は1つの要求またはアクションで1つのタイプのObjectにおいてのみDML操作可能ですしかしながら続く要求においてはDML操作を異なるタイプのObjectで実行可能ですたとえば保存ボタンでアカウントを作成した後に送信ボタンでユーザを作成可能です
大量DML例外処理バルク DML 呼び出しの例外処理方法 (トリガ内の再帰的DML操作も含む) は呼び出し元の場所によって異なる処理がされます
bull Apex DMLステートメントから直接発生したバルクDML呼び出しのためにエラーが発生した場合またはデータベースDMLメソッドの all_or_noneパラメータがTrueとして指定されている場合ランタイムエンジンは「オールオアナッシング」ツールに従います1 回の操作の間すべてのレコードを正常に更新する必要がありまたは全体の操作はDMLステートメントの前の時点に即座に戻ります
bull Forcecom Web Services APIから発生したバルクDML呼び出しのせいでエラーが発生した場合ランタイムエンジンは少なくとも部分保存しようとします
1 最初の試行中ランタイムエンジンはすべてのレコードを処理します有効リールや独自のインデックス違反などの問題によるエラーを生成したレコードは除外されます
2 最初の試行中にエラーがある場合ランタイムエンジンはエラーを生成しなかったレコードのみを含む二回目の試行を行います最初の試行中にエラーをい生成しなかったすべてのレコードが処理されレコードがエラーを生成した場合 おそらくレース状態のせいで それも除外されます
3 二回目の試行中に追加エラーがあった場合ランタイムエンジンは初回と二回目にエラーを生成しなかったレコードのみを含む三回目と最後の試行を行いますレコードがエラーを生成した場合全体操作は失敗しエラーメッセージ「Too many batch retries in the presence of Apex triggers and partial failures」が表示されます
メモ二回目と三回目の試行中にガバナ制限は最初の試行の前のオリジナル状態にリセットされます詳細は「実行ガバナーと制限の理解」を参照してください
Apex 標準クラスおよび標準メソッド
Apex にはプリミティブデータ型の式やより複雑なオブジェクト向けの静的メソッドやインスタンスメソッドを含む標準クラスがあります
参照 Version 180 | 大量DML例外処理 | 205
標準静的メソッドは Java に似ており常に次のような形式となります
Classmethod(args)
プリミティブデータ型の標準静的メソッドに暗黙的なパラメータはなくオブジェクトコンテキストを使用せずに呼び出されますたとえば次の式は 175 の値をその他の値を使用せずに最も近い整数に丸めます
MathroundToLong(175)
すべてのインスタンスメソッドはリストセットまたは文字列など特定のデータ型の式に作成されます例
String s = Hello world
Integer i = slength()
メモ メソッドが nullに評価するオブジェクト式で呼び出される場合Apex ランタイムエンジンはNull ポインタの例外を投げます
一部のクラスではそれらのメソッドのグループ化メカニズムとして名前空間を使用しますたとえばmessage
クラスではApexPages 名前空間を使用します
ApexPagesMessage myMsg = new ApexPagesMessage(ApexPagesFATAL エラーメッセージ)
Apex 標準クラスは次のカテゴリに分類されます
bull Primitivesbull Collectionsbull Enumbull sObjectbull Systembull 例外
Primitives メソッド
Apex Primitive メソッドApex の多くのプリミティブデータ型にはデータの追加処理に使用できるメソッドがありますメソッドのあるプリミティブは次のとおりです
bull Blobbull Booleanbull Datebull Datetimebull Decimalbull Doublebull Longbull String
参照 Version 180 | Primitives メソッド | 206
bull Time
Blob メソッド
次にBlob のシステム静的メソッドを示します
説明戻り値の型引数名前
指定した String Sを Blob に投入します例
String myString = StringToBlob BlobmyBlob = Blobvalueof(myString)
BlobString SvalueOf
次にBlob のインスタンスメソッドを示します
説明戻り値の型引数名前
blob の文字数を返します例String myString = StringToBlob BlobmyBlob = Blobvalueof(myString) Integersize = myBlobsize()
Integersize
blob を String にキャストしますStringtoString
Blob の詳細は「プリミティブデータ型」 (ページ 27)を参照してください
Boolean メソッド
次はBoolean の静的メソッドを示します
説明戻り値の型引数名前
データ型 anyType の履歴管理表の項目である xをBoolean に投入しますanyType データ型の詳細
BooleananyTypexvalueOf
は『Forcecom Web Services API Developers Guide』の「項目のデータ型」を参照してください
Boolean の詳細は詳細はプリミティブデータ型 (ページ 27)を参照してください
Date メソッド
次にDate のシステム静的メソッドを示します
参照 Version 180 | Apex Primitive メソッド | 207
説明戻り値の型引数名前
指定された yearおよび monthの月の日数を返します (1= 1 月)次の例では1960 年の 2 月のに数を示しています
Integer numberDays =datedaysInMonth(1960 2)
IntegerInteger year
Integer month
daysInMonth
指定したyearがうるう年の場合真を返しますBooleanInteger yearisLeapYear
yearmonth (1= 1 月)dayの Integer 表現からDate を構築します次の例では1960 年 2 月 17日を作成します
Date myDate = datenewinstance(1960 217)
DateInteger year
Integer month
Integer date
newInstance
文字列から Date を構築します文字列の形式はローカルの日付形式によって異なります次の例はいくつかのロケールで機能しますdate mydate = dateparse(12272009)
DateString Dateparse
現在の日付を現在のユーザーのタイムゾーンで返します
Datetoday
指定した String の値を含む Date を返しますStringは現地のタイムゾーンの標準の日付形式「yyyy-MM-dd HHmmss」を使用します例string year = 2008 string month =10 string day = 5 string hour =
DateString svalueOf
12 string minute = 20 stringsecond = 20 string stringDate = year+ - + month + - + day + + hour+ + minute + + second
Date myDate = datevalueOf(stringDate)
データ型 anyType の履歴管理表の項目である xをDate に投入しますanyType データ型の詳細は
DateanyTypexvalueOf
『Forcecom Web Services API Developers Guide』の「項目のデータ型」を参照してください
次にDate のインスタンスメソッドを示します
説明戻り値の型引数名前
指定した addlDays数を Date に追加します例
date myDate = datenewInstance(1960 217) date newDate = mydateaddDays(2)
DateInteger addlDaysaddDays
参照 Version 180 | Apex Primitive メソッド | 208
説明戻り値の型引数名前
addlMonthsの指定した数を Date に追加しますDateInteger addlMonthsaddMonths
addlYearsの指定した 数を Date に追加しますDateInteger addlYearsaddYears
Date の day-of-month のコンポーネントを返しますたとえば1999 年 2 月 5 日はday 5 となります
Integerday
Date の day-of-year のコンポーネントを返しますたとえば1999 年 2 月 5 日はday 36 となります
IntegerdayOfYear
メソッドを呼び出した Date と compDateの間の日数を返しますメソッドを呼び出す Date が
IntegerDate compDatedaysBetween
compDateの後に発生する場合戻り値は負となります例
date startDate = datenewInstance(20081 1) date dueDate =datenewInstance(2008 1 30) integernumberDaysDue =startDatedaysBetween(dueDate)
Date を文字列として返しますStringformat
メソッドを呼び出した Date が compDateと同じ場合真を返します例
date myDate = datetoday() date dueDate= datenewInstance(2008 1 30)
BooleanDate compDateisSameDay
boolean dueNow =myDateisSameDay(dueDate)
Date の day-of-month のコンポーネントを返します(1=1 月)
Integermonth
メソッドを呼び出した Date と compDateの間の月数を返します日付の差異は無視されますたと
IntegerDate compDatemonthsBetween
えば同じ年の 3 月 1 日と 3 月 30 日の場合その間の月数は 0 となります
メソッドを呼び出した Date の月の最初の日を返しますたとえば1999 年 7 月 14 日の場合は1999年 7 月 1 日を返します
DatetoStartOfMonth
コンテキストユーザーのロケールに応じてメソッドを呼び出した Date の週の開始日を返しますた
DatetoStartOfWeek
とえばアメリカのロケールでは週は日曜日に始まりヨーロッパでは月曜日に始まります例date myDate = datetoday() dateweekStart = myDatetoStartofWeek()
参照 Version 180 | Apex Primitive メソッド | 209
説明戻り値の型引数名前
Date の year のコンポーネントを返しますIntegeryear
Date の詳細は「プリミティブデータ型」 (ページ 27)を参照してください
Datetime メソッド
次にDatetime のシステム静的メソッドを示します
説明戻り値の型引数名前
DateTime を構築し1970 年 1 月 1 日 000000(GMT) 以降の指定したミリ秒数を表すように初期化します
DatetimeLong lnewInstance
ローカルタイムゾーンの dateおよび timeからDateTime を構築します
DatetimeDate Date
Time Time
newInstance
タイムゾーンの0時にyearmonth (1= 1 月)day
の Integer 表現から Datetime を構築します例
datetime myDate =datetimenewInstance(2008 12 1)
DatetimeInteger year
Integer month
Integer day
newInstance
現地のタイムゾーンで yearmonth (1= 1 月)dayhourminuteおよび secondの Integer 表現から Datetime を構築します例
Datetime myDate =datetimenewInstance(2008 12 1 1230 2)
DatetimeInteger year
Integer month
Integer day
Integer hour
Integer minute
Integer second
newInstance
GMT タイムゾーンの dateおよび timeからDateTime を構築します
DatetimeDate date
Time time
newInstanceGmt
GMT タイムゾーンの0時に yearmonth (1= 1月)dayの Integer 表現から Datetime を構築します
DatetimeInteger year
Integer month
Integer date
newInstanceGmt
GMT タイムゾーンで yearmonth (1= 1 月)dayhourminuteおよび secondの Integer 表現から Datetime を構築します
DatetimeInteger year
Integer month
Integer date
newInstanceGmt
Integer hour
Integer minute
Integer second
参照 Version 180 | Apex Primitive メソッド | 210
説明戻り値の型引数名前
GMT カレンダーに基づいて現在の Datetime を返します例datetime myDateTime = datetimenow()
Datetimenow
返される日付の形式はMMDDYYYY HHMM
PERIODです
ローカルタイムゾーンおよび形式の datetimeから DateTime を構築します次の例はいくつかのロケールで機能します
datetime myDateTime = datetimenow()string mydtstring = mydatetimeformat()
DatetimeString datetimeparse
systemassertequals(12272009 1146AM mydtstring)
指定した String の値を含む Datetime を返しますString は現地のタイムゾーンの標準の日付形式「yyyy-MM-dd HHmmss」を使用します例string year = 2008 string month =10 string day = 5 string hour =
DatetimeString svalueOf
12 string minute = 20 stringsecond = 20 string stringDate = year+ - + month + - + day + + hour+ + minute + + second
Datetime myDate =datetimevalueOf(stringDate)
データ型 anyType の履歴管理表の項目である xをDatetime に投入しますanyType データ型の詳細
DatetimeanyTypexvalueOf
は『Forcecom Web Services API Developers Guide』の「項目のデータ型」を参照してください
指定した String の値を含む Datetime を返しますString はGMT のタイムゾーンの標準の日付形式「yyyy-MM-dd HHmmss」を使用します
DatetimeString svalueOfGmt
次にDatetime のインスタンスメソッドを示します
説明戻り値の型
引数名前
指定した addlDays数を Datetime に追加します例
datetime myDate = datetimenewInstance(1960 2 17) datetime newDate =mydateaddDays(2)
DatetimeInteger addlDaysaddDays
参照 Version 180 | Apex Primitive メソッド | 211
説明戻り値の型
引数名前
指定した addlHoursの数を Datetime に追加しますDatetimeInteger addlHoursaddHours
指定した addlMinutesの数を Datetime に追加しますDatetimeInteger addlMinutesaddMinutes
指定した addlMonthsの数を Datetime に追加しますDatetimeInteger addlMonthsaddMonths
指定した addlSecondsの数を Datetime に追加しますDatetimeInteger addlSecondsaddSeconds
addlYearsの指定した 数を Datetime に追加しますDatetimeInteger addlYearsaddYears
コンテキストユーザーの現地のタイムゾーンで Datetimeの Date のコンポーネントを返します
Datedate
GMT タイムゾーンで Datetime の Date のコンポーネントを返します
DatedateGMT
コンテキストユーザーの現地のタイムゾーンで Datetimeの day-of-month のコンポーネントを返しますたとえ
Integerday
ば1999 年 2 月 5 日 午前 8 時 30 分 12 秒はday 5 となります
GMT タイムゾーンで Datetime の day-of-month のコンポーネントを返しますたとえば1999 年 2 月 5 日午前 8 時 30 分 12 秒はday 5 となります
IntegerdayGmt
コンテキストユーザーの現地のタイムゾーンで Datetimeの day-of-year のコンポーネントを返しますたとえば
IntegerdayOfYear
2008 年 2 月 5 日午前 8 時 30 分 12 秒はday 36 となりますDatetime myDate = datetimenewInstance(2008 2 5 8 30 12) systemassertEquals(myDatedayOfYear() 36)
GMT タイムゾーンで Datetime の day-of-year のコンポーネントを返しますたとえば1999 年 2 月 36 日 午前8 時 30 分 12 秒はday 5 となります
IntegerdayOfYearGmt
現在のユーザーの現地のタイムゾーンを使用してDatetime を文字列として返しますタイムゾーンを指定できない場合はGMT が使用されます
Stringformat
提供された Java の簡単な日付形式と現在のユーザーの現地のタイムゾーンを使用してDatetime を文字列と
StringString dateFormatformat
して返しますタイムゾーンを指定できない場合はGMT が使用されます例datetime myDT = Datetimenow() StringmyDate = myDTformat(hmm a)
Java の簡単な日付形式の詳細はhttpjavasuncomj2se142docsapijavatextSimpleDateFormathtmlを参照してください
参照 Version 180 | Apex Primitive メソッド | 212
説明戻り値の型
引数名前
提供された Java の簡単な日付形式とタイムゾーンを使用してDatetime を文字列として返します提供され
StringString dateFormat
String timezone
format
たタイムゾーンが適切でない場合GMT が使用されます
Java の簡単な日付形式の詳細はhttpjavasuncomj2se142docsapijavatextSimpleDateFormathtmlを参照してください
提供された Java の簡単な日付形式と GMT タイムゾーンを使用してDatetime を文字列として返します
Java の簡単な日付形式の詳細はhttpjavasuncomj2se142docsapijavatextSimpleDateFormathtmlを参照してください
StringString dateFormatformatGmt
秒やタイムゾーンなど現在のユーザーの現地のタイムゾーンを使用してDatetime を文字列として返します
StringformatLong
この DateTime オブジェクトで表された 1970 年 1 月 1日 0 時 0 分 0 秒 (GMT) 以降のミリ秒数を返します
LonggetTime
コンテキストユーザーの現地のタイムゾーンで Datetimeの hour のコンポーネントを返します
Integerhour
GMT タイムゾーンで Datetime の hour のコンポーネントを返します
IntegerhourGmt
コンテキストユーザーの現地のタイムゾーンでメソッドを呼び出した Datetime と compDtが同じ場合真を返します例
datetime myDate = datetimenow() datetimedueDate = datetimenewInstance(2008 1 30)boolean dueNow = myDateisSameDay(dueDate)
BooleanDatetime compDtisSameDay
コンテキストユーザーの現地のタイムゾーンで Datetimeの millisecond のコンポーネントを返します
Integermillisecond
GMT タイムゾーンで Datetime の millisecond のコンポーネントを返します
IntegermillisecondGmt
コンテキストユーザーの現地のタイムゾーンで Datetimeの minute のコンポーネントを返します
Integerminute
GMT タイムゾーンで Datetime の minute のコンポーネントを返します
IntegerminuteGmt
コンテキストユーザーの現地のタイムゾーンで Datetimeの month のコンポーネントを返します (1=1 月)
Integermonth
参照 Version 180 | Apex Primitive メソッド | 213
説明戻り値の型
引数名前
GMT タイムゾーンで Datetime の month のコンポーネントを返します (1= 1 月)
IntegermonthGmt
コンテキストユーザーの現地のタイムゾーンで Datetimeの second のコンポーネントを返します
Integersecond
GMT タイムゾーンで Datetime の second のコンポーネントを返します
IntegersecondGmt
コンテキストユーザーの現地のタイムゾーンで Datetimeの time のコンポーネントを返します
Timetime
GMT タイムゾーンで Datetime の time のコンポーネントを返します
TimetimeGmt
コンテキストユーザーの現地のタイムゾーンで Datetimeの year のコンポーネントを返します
Integeryear
GMT タイムゾーンで Datetime の year のコンポーネントを返します
IntegeryearGmt
Datetime の詳細は「プリミティブデータ型」 (ページ 27)を参照してください
Decimal メソッド
次にDecimal のシステム静的メソッドを示します
説明戻り値の型引数名前
指定した Double の値を含む Decimal を返しますDecimalDouble dvalueOf
指定した Long の値を含む Decimal を返しますDecimalLong lvalueOf
指定した String の値を含む Decimal を返しますJava と同様文字列は署名付きの Decimal を示すものとして解釈されます例String temp = 124567 DecimalmyDecimal = decimalvalueOf(temp)
DecimalString svalueOf
次にDecimal のインスタンスメソッドを示します
説明戻り値の型引数名前
Decimal の絶対値を返しますDecimalabs
参照 Version 180 | Apex Primitive メソッド | 214
説明戻り値の型引数名前
この Decimal を divisorで割りスケールつまり scaleを使用した結果の小数位の数値を設定します次の例でD は 0190 の値を持っています
Decimal D = 19 DDivide(100 3)
DecimalDecimal divisorInteger scale
divide
この Decimal を divisorで割りスケールつまり scaleを使用した結果の小数位の数値を設定し
DecimalDecimal divisorInteger scaleObjectroundingMode
divide
ますそして必要に応じてroundingModeを使用して値を丸めますroundingModeに対して有効な値の詳細は「丸めモード」 (ページ217)例
Decimal myDecimal = 124567 DecimaldivDec = myDecimaldivide (7 2SystemRoundingModeUP)systemassertEquals(divDec 178)
Decimal の Double の値を返しますDoubledoubleValue
指数が必要な場合科学的記数法を使用してこの Decimal の String の値を返します
Stringformat
Decimal の Integer の値を返しますIntegerintValue
Decimal の Long の値を返しますLonglongValue
exponentの指数まで累乗したこの小数の値を返しますexponentの値は -32768 32767 です例
Decimal myDecimal = 412 Decimal powDec= myDecimalpow(2)systemassertEquals(powDec 169744)
DecimalInteger exponentpow
Decimal の桁数を返しますたとえばDecimal の値が 12345 の場合precisionは 5 を返します
Integerprecision
Decimal の値が 123123 の場合precisionは 6を返します例
Decimal D1 = 12345 Integer precision1= D1precision()systemassertEquals(precision1 5)
Decimal D2 = 123123 Integer precision2= D2precision()systemassertEquals(precision2 6)
Decimal の丸められた近似値を返します数値は均等丸めモードを使用して0 の小数位に丸めま
Longround
すつまり2 つの近隣が等距離にない限りは「最
参照 Version 180 | Apex Primitive メソッド | 215
説明戻り値の型引数名前
近隣」に等距離にある場合このモードは均等な近隣に対して丸めますこの丸めモードは統計的に連続する計算に対して繰り返し適用される場合累積エラーを最小化します均等丸めモードの詳細は 「丸めモード」 (ページ 217)を参照してください例
Decimal D1 = 55 Long L1 = D1round()systemassertEquals(L1 6)
Decimal D2= 52 Long L2= D2round()systemassertEquals(L2 5)
Decimal D3= -57 Long L3= D3round()systemassertEquals(L3 -6)
Decimal の丸められた近似値を返します数値はroundingModeで指定された丸めモードを使用し
LongSystemRoundingModeroundingMode
round
て0 の小数位に丸められますroundingModeに対して有効な値の詳細は 「丸めモード」 (ページ 217)
Decimal のスケールつまり小数位の数を返します
Integerscale
必要に応じて均等丸めモードを使用しDecimalのスケールを小数位の指定された数に設定します
DecimalInteger scalesetScale
均等丸めモードは2 つの近隣が等距離にない限りは「最近隣」に等距離にある場合このモードは均等な近隣に丸めます均等丸めモードの詳細は 「丸めモード」 (ページ 217)を参照してくださいscaleの値は -33 33 です
Decimal のスケールを明示的に設定しない場合スケールは Decimal が作成された項目によって指定されます
bull Decimal がクエリの一部として作成される場合スケールはクエリから返される項目のスケールに基づきます
bull Decimal が String から作成される場合スケールは String の小数点の後の文字数となります
bull Decimal が小数以外の数値から作成される場合スケールは数値を String に変換し小数点以下の文字数を指定して決定します
必要に応じて roundingMode で指定された丸めモードを使用しDecimal のスケールを小数位の
DecimalInteger scaleSystemRoundingModeroundingMode
setScale
指定された数に設定しますroundingModeに対
参照 Version 180 | Apex Primitive メソッド | 216
説明戻り値の型引数名前
して有効な値の詳細は 「丸めモード」 (ページ217)scaleの値は -32768 32767 です
Decimal のスケールを明示的に設定しない場合スケールは Decimal が作成された項目によって指定されます
bull Decimal がクエリの一部として作成される場合スケールはクエリから返される項目のスケールに基づきます
bull Decimal が String から作成される場合スケールは String の小数点の後の文字数となります
bull Decimal が小数以外の数値から作成される場合スケールは数値を String に変換し小数点以下の文字数を指定して決定します
後続の 0 を削除した Decimal を返しますDecimalstripTrailingZeros
科学的記数法を使用せずにDecimal の String の値を返します
StringtoPlainString
Decimal の詳細は「プリミティブデータ型」 (ページ 27)を参照してください
丸めモード
丸めモードでは小数部を破棄できる数値演算の丸め動作を指定します各丸めモードでは丸められた結果の返される下位の桁をどのように計算するかを指定します次はroundingModeの有効な値を示します
説明名前
正の無限大に丸めますつまり結果が正の場合このモードはUP丸めモードと同じ動作をします結果が負の場合DOWN丸めモードと同じ動作をしますこの丸めモードで計算された値は小さくなりません例
CEILING
bull 入力値 55 CEILING丸めモードの結果 6bull 入力値 11 CEILING丸めモードの結果 2bull 入力値 -11 CEILING丸めモードの結果 -1bull 入力値 -27 CEILING丸めモードの結果 -2
0 に丸めますこの丸めモードは常に端数 (小数部分) を実行前に破棄しますこの丸めモードを使用しても計算された値の絶対値は大きくなりません例
DOWN
bull 入力値 55 DOWN丸めモードの結果 5bull 入力値 11 DOWN丸めモードの結果 1bull 入力値 -11 DOWN丸めモードの結果 -1bull 入力値 -27 DOWN丸めモードの結果 -2
参照 Version 180 | Apex Primitive メソッド | 217
説明名前
負の無限大に丸めますつまり結果が正の場合このモードはDOWN丸めモードと同じ動作をします結果が負の場合UP丸めモードと同じ動作をしますこの丸めモードで計算された値は大きくなりません例
FLOOR
bull 入力値 55 FLOOR丸めモードの結果 5bull 入力値 11 FLOOR丸めモードの結果 1bull 入力値 -11 FLOOR丸めモードの結果 -2bull 入力値 -27 FLOOR丸めモードの結果 -3
2 つの近隣が等距離にない限りは「最近隣」に丸め等距離にある場合このモードは端数を切り捨てます破棄した端数 (小数部分が) 05 より大きい場合
HALF_DOWN
この丸めモードはUP丸めモードと同じ動作をします05 より小さい場合はDOWN丸めモードと同じ動作をします例bull 入力値 55 HALF_DOWN丸めモードの結果 5bull 入力値 11 HALF_DOWN丸めモードの結果 1bull 入力値 -11 HALF_DOWN丸めモードの結果 -1bull 入力値 -27 HALF_DOWN丸めモードの結果 -2
2 つの近隣が等距離にない限りは「最近隣」に丸め等距離にある場合このモードは均等な近隣に丸めます破棄した端数 (小数部分) の左側の桁が奇数の
HALF_EVEN
場合この丸めモードは HALF_UP丸めモードと同じ動作をします偶数である場合HALF_DOWN丸めメソッドと同じ動作をします例bull 入力値 55 HALF_EVEN丸めモードの結果 6bull 入力値 11 HALF_EVEN丸めモードの結果 1bull 入力値 -11 HALF_EVEN丸めモードの結果 -1bull 入力値 -27 HALF_EVEN丸めモードの結果 -3
この丸めモードは統計的に連続する計算に対して繰り返し適用される場合累積エラーを最小化します
2 つの近隣が等距離にない限りは「最近隣」に丸め等距離にある場合このモードは端数を切り上げます破棄した端数 (小数部分が) 05 以上の場合この
HALF_UP
丸めモードはUP丸めメソッドと同じ動作をします05 以下の場合はDOWN
丸めメソッドと同じ動作をします例bull 入力値 55 HALF_UP丸めモードの結果 6bull 入力値 11 HALF_UP丸めモードの結果 1bull 入力値 -11 HALF_UP丸めモードの結果 -1bull 入力値 -27 HALF_UP丸めモードの結果 -3
要求された演算によって正確な結果が出たことを確認しますつまり丸めは必要ありませんこの丸めモードが正確でない結果を生成する演算に指定されて場合Exception が投げられます例
UNNECESSARY
bull 入力値 55 UNNECESSARY丸めモードの結果 Exceptionbull 入力値 10 UNNECESSARY丸めモードの結果 1
参照 Version 180 | Apex Primitive メソッド | 218
説明名前
0 から遠い方向に丸めますこの丸めモードは常に端数 (小数部分) を実行前に切り捨てますこの丸めモードを使用しても計算された値の絶対値は小さくなりません例
UP
bull 入力値 55 UP丸めモードの結果 6bull 入力値 11 UP丸めモードの結果 2bull 入力値 -11 UP丸めモードの結果 -2bull 入力値 -27 UP丸めモードの結果 -3
Double メソッド
次にDouble のシステム静的メソッドを示します
説明戻り値の型引数名前
データ型 anyType の履歴管理表の項目である xをDouble に投入しますanyType データ型の詳細は
DoubleanyTypexvalueOf
『Forcecom Web Services API Developers Guide』の「項目のデータ型」を参照してください
指定した String の値を含む Double を返しますJava と同様String は署名付きの Double を示すものとして解釈されます例Double DD1 = doublevalueOf(314159)
DoubleString svalueOf
次にDouble のインスタンスメソッドを示します
説明戻り値の型引数名前
この Double の文字列値を返しますStringformat
Double の Integer の値を Integer に投入して返します例Double DD1 = doublevalueOf(314159)Integer value = DD1intValue()systemassertEquals(value 3)
IntegerintValue
この Double の Long の値を返しますLonglongValue
この Double の丸めた値を返します数値は均等丸めモードを使用して0 の小数位に丸めますつ
Longround
まり2 つの近隣が等距離にない限りは「最近隣」に等距離にある場合このモードは均等な近隣に対して丸めますこの丸めモードは統計的に連続する計算に対して繰り返し適用される場合累積エラーを最小化します均等丸めモードの詳
参照 Version 180 | Apex Primitive メソッド | 219
説明戻り値の型引数名前
細は 「丸めモード」 (ページ 217)を参照してください例
Double D1 = 55 Long L1 = D1round()systemassertEquals(L1 6)
Double D2= 52 Long L2= D2round()systemassertEquals(L2 5)
Double D3= -57 Long L3= D3round()systemassertEquals(L3 -6)
Double の詳細は「プリミティブデータ型」 (ページ 27)を参照してください
Integer メソッド
次にInteger のシステム静的メソッドを示します
説明戻り値の型引数名前
データ型 anyType の履歴管理表の項目である xをInteger に投入しますanyType データ型の詳細は
IntegeranyTypexvalueOf
『Forcecom Web Services API Developers Guide』の「ファイルのデータ型」を参照してください
指定した String の値を含む Integer を返しますJava と同様String は署名付きの 10 進数整数を示すものとして解釈されます例Integer myInt = integervalueOf(123)
IntegerString svalueOf
次にInteger のインスタンスメソッドを示します
説明戻り値の型引数名前
Integer を文字列として返しますStringformat
Integer の詳細は「プリミティブデータ型」 (ページ 27)を参照してください
Long メソッド
次にLong のシステム静的メソッドを示します
参照 Version 180 | Apex Primitive メソッド | 220
説明戻り値の型引数名前
指定した String の値を含む Long を返しますJavaと同様文字列は符号付きの小数 Long を示すものとして解釈されます例Long L1 = longvalueOf(123456789)
LongString svalueOf
次にLong のインスタントメソッドを示します
説明戻り値の型引数名前
この Long の文字列形式を返しますStringformat
Long の Integer の値を返しますIntegerintValue
Long の詳細は「プリミティブデータ型」 (ページ 27)を参照してください
String メソッド
次にString のシステム静的メソッドを示します
説明戻り値の型引数名前
String sの単一引用符の前にエスケープ文字 () を追加した String を返しますこのメソッドは動的
StringString sescapeSingleQuotes
SOQL ステートメントを作成する場合に役に立ちSOQL インジェクションを回避します動的SOQL の詳細は「動的 SOQL」 (ページ 140)を参照してください
現在の文字列をapexoutputText と同じ方法で置換に使用するパターンとして扱います
StringString s
ListltStringgtarguments
format
整数のリストの値から文字列を返しますStringListltIntegergtcharArray
fromCharArray
指定した Date を示す String を標準の「yyyy-MM-dd」形式で返します例Date myDate = DateToday() String sDate= StringvalueOf(myDate)
StringDate dvalueOf
指定した Datetime を示す String を現地のタイムゾーンの標準「yyyy-MM-dd HHmmss」形式で返します
StringDatetime dtvalueOf
指定された Decimal を示す String を返しますStringDecimal dvalueOf
参照 Version 180 | Apex Primitive メソッド | 221
説明戻り値の型引数名前
データ型 anyType の履歴管理表の項目である xをString に投入します例
Double myDouble = 1234 String myString= StringvalueOf(myDouble)SystemassertEquals(1234 myString)
StringanyType xvalueOf
anyType データ型の詳細は『Forcecom Web ServicesAPI Developers Guide』の「項目のデータ型」を参照してください
指定した Datetime を示す String を GMT タイムゾーンの標準「yyyy-MM-dd HHmmss」形式で返します
StringDatetime dtvalueOfGmt
次にString のインスタンスメソッドを示します
説明戻り値の型引数名前
String の各文字の Unicode 値に基づいて2 つの文字列を辞書編集的に比較します結果は次のとおりです
IntegerString compStringcompareTo
bull メソッドをコールした String が辞書編集的にcompStringの前に来る場合は負の Integer
bull メソッドをコールした String が辞書編集的にcompStringの後に来る場合は正の Integer
bull Strings が等しい場合 0
Strings が異なる索引位置がない場合辞書編集的には短い String が長い String の後に来ます例
String myString1 = abcde StringmyString2 = abcd Integer result =myString1compareTo(myString2)SystemassertEquals(result 1)
equalsメソッドが真を返す場合このメソッドは 0 を返します
メソッドをコールした String に compStringの指定した連続する文字が含まれている場合にのみtrueを返します例
String myString1 = abcde StringmyString2 = abcd Boolean result =
BooleanString compStringcontains
myString1contains(myString2)SystemassertEquals(result true)
参照 Version 180 | Apex Primitive メソッド | 222
説明戻り値の型引数名前
メソッドをコールした String が suffixで終わる場合trueを返します
BooleanString suffixendsWith
compStringが null でなくメソッドをコールした String と同じ 2 進数列の文字を示す場合true
BooleanString compStringequals
を返しますcompareToメソッドが 0 を返す場合このメソッドは真を返します例
String myString1 = abcde StringmyString2 = abcd Boolean result =myString1equals(myString2)SystemassertEquals(result false)
==演算子は String も比較も行いますが大文字と小文字を区別して Apex セマンティックに一致させます(==はID を比較する場合も同じ理由で大文字と小文字を区別します)
compStringが null でなくメソッドをコールした String と同じ連続する文字を示す場合trueを返します大文字と小文字は無視します例
String myString1 = abcd StringmyString2 = ABCD Boolean result =
BooleanString compStringequalsIgnoreCase
myString1equalsIgnoreCase(myString2)SystemassertEquals(result true)
指定したサブ文字列が最初に発生した索引を返しますサブ文字列がない場合このメソッドは -1を返します
IntegerString subStringindexOf
索引 iの位置から指定されたサブ文字列が最初に発生する索引を返しますサブ文字列がない場合このメソッドは -1 を返します例
String myString1 = abcd StringmyString2 = bc Integer result =
IntegerString substring
Integer i
indexOf
myString1indexOf(myString2 0)SystemassertEquals(result 1)
指定したサブ文字列が最後に発生した索引を返しますサブ文字列がない場合このメソッドは -1を返します
IntegerString substringlastIndexOf
String に含まれる 16 ビット Unicode 文字の数を返します例String myString = abcd Integer result= myStringlength()SystemassertEquals(result 4)
Integerlength
参照 Version 180 | Apex Primitive メソッド | 223
説明戻り値の型引数名前
リテラルターゲットシーケンス targetに一致する文字列のサブ文字列と指定したリテラル置換シーケンス replacementと置き換えます
StringString target
String replacement
replace
正規表現 regExpに一致する文字列のサブ文字列と置換シーケンス replacementと置き換えま
StringString regExp
String replacement
replaceAll
す正規表現の詳細はhttpjavasuncomj2se150docsapijavautilregexPatternhtmlを参照してください
正規表現 regExpに一致する文字列の最初のサブ文字列と置換シーケンスreplacementと置き換
StringString regExp
String replacement
replaceFirst
えます正規表現の詳細はhttpjavasuncomj2se150docsapijavautilregexPatternhtmlを参照してください
文字列の各サブ文字列を含むリストを返しますこのサブ文字列は正規表現regExpまたは文字
String[]String regExp
Integer limit
split
列の末尾に達したことにより終了します正規表現の詳細はhttpjavasuncomj2se150docsapijavautilregexPatternhtmlを参照してください
このサブ文字列は文字列の中で発生した順序でリストに記述されます regExpが String の一部に一致しない場合結果リストには元の文字列を含む要素が 1 つだけ含まれます
オプションの limitパラメータはパターンが適用された回数を制御するためリストの長さに影響を与えます
bull limitが 0 より大きい場合パターンは最大limit - 1 回適用されたことになりますまたリストの長さは最大 limitとなりリストの最後のエントリには最後に一致した区切り文字移行のすべての入力が含まれます
bull limitが正の値でない場合パターンを何度でも適用することが可能となりリストの長さも任意となります
bull limitが 0 の場合パターンは何度でも適用することが可能となりリストの長さも任意となりますが残りの続く空の文字列は破棄されます
たとえばString s = booandfooの場合次のようになります
bull ssplit( 2)は boo andfooを生成します
参照 Version 180 | Apex Primitive メソッド | 224
説明戻り値の型引数名前
bull ssplit( 5)はboo and foo
を生成しますbull ssplit( -2)は boo and
fooを生成しますbull ssplit(o 5)は b andf
を生成しますbull ssplit(o -2)は b andf
を生成しますbull ssplit(o 0)は b andf
を生成します
メソッドをコールした String が prefixで始まる場合trueを返します
BooleanString prefixstartsWith
指定した startIndexの文字で始まり String の末尾まで続く新しい String を返します
StringInteger startIndexsubstring
指定した startIndexの文字で始まり endIndex -1 の文字まで続く新しい String を返します例
hamburgersubstring(4 8) Returnsurge
StringInteger startIndex
Integer endIndex
substring
smilessubstring(1 5) Returnsmile
String のすべての文字をデフォルトのロケールの規則を使用して小文字に変換します
StringtoLowerCase
String のすべての文字を指定したロケールの規則を使用して小文字に変換します
StringString localetoLowerCase
String のすべての文字をデフォルトのロケールの規則を使用して大文字に変換します例String myString1 = abcd StringmyString2 = ABCD myString1 =
StringtoUpperCase
myString1toUpperCase() Boolean result= myString1equals(myString2)SystemassertEquals(result true)
String のすべての文字を指定したロケールの規則を使用して大文字に変換します
StringString localetoUpperCase
先頭末尾のスペースタブ改行文字など空白文字を含まない String を返します
Stringtrim
String の詳細は「プリミティブデータ型」 (ページ 27)を参照してください
参照 Version 180 | Apex Primitive メソッド | 225
Time メソッド
次にTime のシステム静的メソッドを示します
説明戻り値の型引数名前
hourminutessecondsおよびmilliseconds
の Integer 表現から Time を構築します次の例では1820220 の時間を作成します
Time myTime = TimenewInstance(18 302 20)
TimeInteger hour
Integer minutes
Integer seconds
Integermilliseconds
newInstance
次にTime のインスタンスメソッドを示します
説明戻り値の型引数名前
指定した addlHoursの数を Time に追加しますTimeInteger addlHoursaddHours
指定した addlMillisecondsの数を Time に追加します
TimeIntegeraddlMilliseconds
addMilliseconds
指定した addlMinutesの数を Time に追加します例
Time myTime = TimenewInstance(18 302 20)
TimeIntegeraddlMinutes
addMinutes
Integer myMinutes = myTimeminute()myMinutes = myMinutes + 5
SystemassertEquals(myMinutes 35)
指定した addlSecondsの数を Time に追加します
TimeIntegeraddlSeconds
addSeconds
Time の hour のコンポーネントを返します例Time myTime = TimenewInstance(18 302 20)
Integerhour
myTime = myTimeaddHours(2)
Integer myHour = myTimehour()SystemassertEquals(myHour 20)
Time の millisecond のコンポーネントを返しますIntegermillisecond
Time の minute のコンポーネントを返しますIntegerminute
Time の second のコンポーネントを返しますIntegersecond
Time の詳細は「プリミティブデータ型」 (ページ 27)を参照してください
参照 Version 180 | Apex Primitive メソッド | 226
Apex Collection メソッド
Apex Collection メソッドApex のすべてのコレクションにはそれらに関連するメソッドがありデータを割り当て取得および処理しますコレクションは次のとおりです
bull Listbull Mapbull Set
メモ 保持できる項目の数については制限はありませんただしヒープサイズには制限があります
List メソッド
リストメソッドはすべてのインスタンスメソッドでリストの特定のインスタンスに操作されますたとえば次のコードは myListからすべての要素を削除します
myListclear()
clearメソッドにはパラメータは含まれませんがそれをコールするリスト自身が暗黙的なパラメータです
次にList のインスタンスパラメータを示します
メモ 以下の表ではList_elemはリストと同じデータ型の単一の要素を示します
説明戻り値の型引数名前
リストの最後に要素 eを追加します例
ListltIntegergt myList = newListltIntegergt() myListadd(47) Integer
VoidAny typeeadd
myNumber = myListget(0)systemassertEquals(myNumber 47)
要素 eをリストの索引位置 iで追加します次の例では 6 つの要素を持つリストが作成され整数が最初と 2 番目の索引位置に追加されます
ListltIntegergt myList = new Integer[6]myListadd(0 47) myListadd(1 52)systemassertEquals(myListget(1) 52)
VoidInteger i
Any typee
add
リスト lのすべての要素がメソッドをコールするリストに追加されます2 つのリストは同じデータ型である必要があります
VoidList laddAll
参照 Version 180 | Apex Collection メソッド | 227
説明戻り値の型引数名前
セット sのすべての要素がメソッドをコールするリストに追加されますセットとリストのタイプは同じでなければなりません
VoidSet saddAll
すべての要素をリストから削除し続いてリストの長さを 0 に設定します
Voidclear
リストの複製コピーを作成します
これが sObject レコードのリストである場合複製リストはリストの浅いコピーとなりますつま
List (同じデータ型)clone
り複製には各オブジェクトに対する参照がありますがsObject レコード自体は複製されません例
Account a = new Account(name=Acmebillingcity=New York) Account b = newAccount() Account[] l1 = newAccount[]ab Account[] l2 =l1clone() l1[0]billingcity = SanFrancisco SystemassertEquals(l1[0]billingcity San Francisco)SystemassertEquals( l2[0]billingcitySan Francisco)
sObject レコードもコピーするにはdeepClone
メソッドを使用する必要があります
sObject レコード自体を含めsObject レコードのリストの複製コピーを作成します例Account a = new Account(name=Acmebillingcity=New York) Account b = new
List (同じオブジェクトタイプ)
Booleanopt_preserve_id
deepClone
Account() Account[] l1 = newAccount[]ab Account[] l2 =l1deepClone() l1[0]billingcity = SanFrancisco SystemassertEquals(l1[0]billingcity San Francisco)SystemassertEquals( l2[0]billingcityNew York)
メモ deepCloneはプリミティブデータ型のリストではなくsObject のリストにのみ動作します
オプションの opt_preserve_id引数は元のオブジェクトの ID を複製で保持するかまたは削除するかを指定します
リストが含む sObject レコードを複製せずにリストの浅いコピーを作製するにはclone()メソッドを使用します
参照 Version 180 | Apex Collection メソッド | 228
説明戻り値の型引数名前
索引 iに保存されたリスト要素を返します例
ListltIntegergt myList = newListltIntegergt() myListadd(47) Integer
Array_elemInteger iget
myNumber = myListget(0)systemassertEquals(myNumber 47)
プリミティブデータ型または sObjects の一次元リストの要素を参照するためにリスト名の後に要素の索引の位置を大かっこで囲んで表記します例
ListltStringgt colors = new String[3]colors[0] = Red colors[1] = Bluecolors[2] = Green
sObject のリストを構成する sObjects タイプのトークンを返します定義情報とともに使用してリ
SchemaSObjectTypegetSObjectType
ストに特定の種類の sObjects を含むかどうかを指定します例public class listTest 一般的なsObject 変数 s を作成 SObject s =Databasequery (SELECT Id FROM AccountLIMIT 1)
sObject 変数が 取引先のトークンであるかを確認SystemassertEquals(sgetSObjectType()AccountsObjectType)
一般的な sObjects のリストを作成ListltsObjectgt l = new Account[]
sObject のリストに 取引先のトークンが含まれているかを確認SystemassertEquals(sgetSObjectType()AccountsObjectType)
このメソッドは sObjects から構成されているリストとともにのみ使用できます
詳細は「Apex 定義情報について」 (ページ 135)を参照してください
リストの要素が 0 の場合True を返しますBooleanisEmpty
イタレータのインスタンスを返しますイタレータから反復可能なメソッドhasNextおよびnext
を使用してリスト内で反復できます例
global class CustomIterable implementsIteratorltAccountgt ListltAccountgt accs
イタレータiterator
get set Integer i get set public
参照 Version 180 | Apex Collection メソッド | 229
説明戻り値の型引数名前CustomIterable() accs = [SELECT idname numberofEmployees FROM AccountWHERE name = false] i = 0 globalboolean hasNext() if(i gt= accssize())return false else return true global Account next() if(i == 8) i++return null i=i+1 return accs[i-1]
メモ リストで iterableメソッドを使用するために iterableインターフェースを使用する必要はありません
リストの i番目の索引で保存された要素を削除し削除された要素を返します例
ListltStringgt colors = new String[3]colors[0] = Red colors[1] = Blue
Array_elemInteger iremove
colors[2] = Green String S1 =colorsremove(2)systemassertEquals(S1 Green)
eをリストの索引 iの位置に割り当てます例
ListltIntegergt myList = new Integer[6]myListset(0 47) myListset(1 52)systemassertEquals(myListget(1) 52)
VoidInteger i
Any typee
set
プリミティブデータ型または sObjects の一次元リストの要素を設定するためにリスト名の後に要素の索引の位置を大かっこで囲んで表記します例
ListltStringgt colors = new String[3]colors[0] = Red colors[1] = Bluecolors[2] = Green
リストの要素の数を返します例ListltIntegergt myList = newListltIntegergt() Integer size =
Integersize
myListsize() systemassertEquals(size0)
ListltIntegergt myList2 = new Integer[6]Integer size2 = myList2size()systemassertEquals(size2 6)
リスト内の項目を昇順で並べ替えますプリミティブデータ型で構成されているリストとともにのみ
Voidsort
このメソッドを使用できます次の例でリストには 3 つの要素がありますリストを並べ替える
参照 Version 180 | Apex Collection メソッド | 230
説明戻り値の型引数名前
場合最初の要素には値が割り当てられていないため null で2 番目の要素の値は 5 となりますListltIntegergt L1 = new Integer[3] Assign values to the first twoelements L1[0] = 10 L1[1] = 5L1sort() First element is nullsecond is 5systemassertEquals(L1get(1) 5)
リストについての詳細はリスト (ページ 34)を参照してください
Map メソッド
マップメソッドはすべてのインスタンスメソッドでマップの特定のインスタンスに操作されます次にマップのインスタンスメソッドを示します
メモ 以下の表では次のようになります
bull Key_typeはマップキーのプリミティブデータ型を示しますbull Value_typeマップ値のプリミティブまたは sObject データ型を示しま
す
説明戻り値の型引数名前
マップからすべてのキー値マッピングを削除しますVoidclear
マップの複製コピーを作成します
これが sObject レコード値のマップである場合複製マップはマップの浅いコピーとなりますつまり複製
Map (同じデータ型)
clone
には各オブジェクトレコードに対する参照がありますがsObject レコード自体は複製されません例
Account a = new Account(name=Acmebillingcity=New York)
MapltInteger Accountgt map1 = newMapltInteger Accountgt
map1put(1 a)
MapltInteger Accountgt map2 = map1clone()
map1get(1)billingcity = San Francisco
SystemassertEquals(map1get(1)billingcitySan Francisco)SystemassertEquals(map2get(1)billingcitySan Francisco)
sObject レコードもコピーするにはdeepCloneメソッドを使用する必要があります
参照 Version 180 | Apex Collection メソッド | 231
説明戻り値の型引数名前
マップに指定された keyのマッピングが含まれている場合は真を返します例
Mapltstring stringgt colorCodes = newMapltString Stringgt() colorCodesput(Red
Booleanキータイプ keycontainsKey
FF0000) colorCodesput(Blue0000A0) Boolean contains =colorCodescontainsKey(Blue)SystemassertEquals(contains True)
sObject レコード値を含むマップである場合sObject レコードなどの複製コピーを作成します例Account a = new Account(name=Acmebillingcity=New York)
Map (同じデータ型)
deepClone
MapltInteger Accountgt map1 = newMapltInteger Accountgt map1put(1 a)
MapltInteger Accountgt map2 =map1deepClone()
map1get(1)billingcity = San Francisco
SystemassertEquals(map1get(1)billingcity San Francisco)SystemassertEquals(map2get(1)billingcity New York)
リストが含む sObject レコードを複製せずにマップの浅いコピーを作製するにはclone()メソッドを使用します
指定した keyがマップされる値またはマップにこのキーの値が含まれていない場合nullを返します例
MapltString Stringgt colorCodes = newMapltString Stringgt() colorCodesput(Red
Value_typeキータイプ keyget
FF0000) colorCodesput(Blue0000A0) String code =colorCodesget(Blue)SystemassertEquals(code 0000A0)
次はマップ内の 色ではありません Stringcode2 = colorCodesget(Magenta)SystemassertEquals(code2 null)
マップ値を構成する sObjects タイプのトークンを返します定義情報とともに使用してマップに特定の種類の sObjects を含むかどうかを指定します例public class mapTest 一般的な sObject変数 s を作成 SObject s = Databasequery
SchemaSObjectTypegetSObjectType
(SELECT Id FROM Account LIMIT 1)
sObject 変数が 取引先のトークンであるかを確認 SystemassertEquals(sgetSObjectType()
参照 Version 180 | Apex Collection メソッド | 232
説明戻り値の型引数名前AccountsObjectType)
一般的な sObjects のマップを作成 MapltIntegerAccountgt M = new MapltInteger Accountgt()
sObjects のリストに 取引先のトークンが含まれているかを確認SystemassertEquals(MgetSObjectType()AccountsObjectType)
このメソッドは sObjects 値を持つマップとともにのみ使用できます
詳細は「Apex定義情報について」 (ページ135)を参照してください
マップに内のキー値ペアが空の場合True を返します例MapltString Stringgt colorCodes = newMapltString Stringgt() Boolean empty =
BooleanisEmpty
colorCodesisEmpty()systemassertEquals(empty true)
マップのすべてのキーを含むセットを返します例MapltString Stringgt colorCodes = newMapltString Stringgt() colorCodesput(Red
Key_typeのセット
keySet
FF0000) colorCodesput(Blue0000A0) Set ltStringgt colorSet = newSetltStringgt() colorSet =colorCodeskeySet()
指定した valueとマップの keyを関連付けますマップぬすでにこのキーのマッピングを含む場合以前の値はメソッドで返されその後置き換えられます例
MapltString Stringgt colorCodes = newMapltString Stringgt() colorCodesput(Red
Value_typeKey key
Value value
put
ff0000) colorCodesput(RedFF0000) Red is now FF0000
指定したマップmからのすべてのマッピングを元のマップにコピーしますmからの新しいマッピングは元のマップにのマッピングを置き換えます
VoidMap mputAll
マップが sObjects に対する IDs または Strings である場合sObject レコード lのリストをこの入力のマップコンストラクタと同じ方法でマップに追加します
sObject[] lputAll
keyこのキーのマッピング (ある場合) をマップから削除します値はメソッドで返され削除されます例
MapltString Stringgt colorCodes = newMapltString Stringgt() colorCodesput(Red
Value_typeKey keyremove
参照 Version 180 | Apex Collection メソッド | 233
説明戻り値の型引数名前FF0000) colorCodesput(Blue0000A0) String myColor =colorCodesremove(Blue) String code2 =colorCodesget(Blue)SystemassertEquals(code2 null)
マップのキー値のペアの数を返します例MapltString Stringgt colorCodes = newMapltString Stringgt() colorCodesput(Red
Integersize
FF0000) colorCodesput(Blue0000A0) Integer mSize =colorCodessize()systemassertEquals(mSize 2)
マップのすべての値を含むリストを順不同で返します例MapltString Stringgt colorCodes = newMapltString Stringgt() colorCodesput(Red
Value_typeのリスト
values
FF0000) colorCodesput(Blue0000A0) ListltStringgt colors = newListltStringgt() colors =colorCodesvalues()
マップについての詳細はマップ (ページ 36)を参照してください
Set メソッド
Set メソッドはセットつまり setキーワードを使用して初期化されたプリミティブの順序が指定されていないコレクションに機能しますSet メソッドはすべてのインスタンスメソッドでセットの特定のインスタンスに操作されます次にSet のインスタンスメソッドを示します
メモ 以下の表ではSet_elemはセットと同じデータ型の単一の要素を示しますSet にはプリミティブデータ型のみを含みます
説明戻り値の型引数名前
まだ存在しない場合は要素を Set に追加します
このメソッドは元のセットがコールの結果として変更された場合に真を返します例
setltstringgt myString = newSetltStringgta b c Boolean
BooleanSet 要素 eadd
result result = myStringadd(d)systemassertEquals(result true)
まだ存在しない場合指定されたリストのすべての要素をセットに追加しますこのメソッドは
BooleanList laddAll
リストとセットの union を生成しますリストは
参照 Version 180 | Apex Collection メソッド | 234
説明戻り値の型引数名前
メソッドをコールするセットと同じ型でなければなりません
このメソッドは元のセットがコールの結果として変更された場合に trueを返します
まだ存在しない場合指定されたセットのすべての要素をメソッドをコールするセットに追加しま
BooleanSet saddAll
すこのメソッドは2 つのセットの unionを生成します指定されたセットはメソッドをコールする元のセットと同じ型でなければなりません
このメソッドは元のセットがコールの結果として変更された場合に真を返します例
setltstringgt myString = newSetltStringgta b setltstringgtsString = new SetltStringgtc
Boolean result1 result1 =myStringaddAll(sString)systemassertEquals(result1 true)
セットからすべての要素を削除しますVoidclear
セットの複製コピーを作成しますSet (同じデータ型)clone
セットに指定した要素がある場合trueを返します例
setltstringgt myString = newSetltStringgta b Boolean result
BooleanSet 要素 econtains
result = myStringcontains(z)systemassertEquals(result false)
指定したリストにすべての要素がある場合真を返しますリストはメソッドをコールするセットと同じ型でなければなりません
BooleanList lcontainsAll
指定したセットにすべての要素がある場合真を返します指定されたセットはメソッドをコー
BooleanSet scontainsAll
ルする元のセットと同じ型でなければなりません例setltstringgt myString = newSetltStringgta b setltstringgtsString = new SetltStringgtcsetltstringgt rString = newSetltStringgta b c
Boolean result1 result2 result1 =myStringaddAll(sString)systemassertEquals(result1 true)
参照 Version 180 | Apex Collection メソッド | 235
説明戻り値の型引数名前result2 = myStringcontainsAll(rString)systemassertEquals(result2 true)
セットの要素が 0 の場合True を返します例Setltintegergt mySet = new Setltintegergt()Boolean result result =
BooleanisEmpty
mySetisEmpty()systemassertEquals(result true)
存在する場合は指定した要素をセットから削除します
このメソッドは元のセットがコールの結果として変更された場合に真を返します
BooleanSet 要素 eremove
存在する場合は指定したリストの要素をセットから削除しますこのメソッドは2 つのセットの
BooleanList lremoveAll
relative compliment を生成しますリストはメソッドをコールするセットと同じ型でなければなりません
このメソッドは元のセットがコールの結果として変更された場合に真を返します例
Setltintegergt mySet = new Setltintegergt12 3 Listltintegergt myList = newListltintegergt1 3 Boolean result =mySetremoveAll(myList)SystemassertEquals(result true)
Integer result2 = mySetsize()SystemassertEquals(result2 1)
存在する場合は指定したセットの要素を元のセットから削除しますこのメソッドは2 つのセッ
BooleanSet sremoveAll
トの relative compliment を生成します指定されたセットはメソッドをコールする元のセットと同じ型でなければなりません
このメソッドは元のセットがコールの結果として変更された場合に真を返します
指定したリストに含まれるこのセットの要素のみを保持しますこのメソッドはリストとセット
BooleanList lretainAll
の intersection を生成しますリストはメソッドをコールするセットと同じ型でなければなりません
このメソッドは元のセットがコールの結果として変更された場合に真を返します例
Setltintegergt mySet = new Setltintegergt12 3 Listltintegergt myList = new
参照 Version 180 | Apex Collection メソッド | 236
説明戻り値の型引数名前Listltintegergt1 3 Boolean result =mySetretainAll(myList)
SystemassertEquals(result true)
指定したセットに含まれる元のセットの要素のみを保持しますこのメソッドは2 つのセットの
BooleanSet sretainAll
intersection を生成します指定されたセットはメソッドをコールする元のセットと同じ型でなければなりません
このメソッドは元のセットがコールの結果として変更された場合に真を返します
セットの要素の数 (基数) を返します例Setltintegergt mySet = new Setltintegergt12 3 Listltintegergt myList = new
Integersize
Listltintegergt1 3 Boolean result =mySetretainAll(myList)
SystemassertEquals(result true)
Integer result2 = mySetsize()SystemassertEquals(result2 2)
セットについての詳細は「セット」 (ページ 35)を参照してください
Enum メソッドEnum 値はユーザー定義のメソッドを追加できませんがシステム Enum 値を含むすべての Enum 値は次のメソッドを Apex で定義します
説明戻り値の型引数名前
Enum 項目の名前を String として返します
Stringname
0 から始まる Enum 値のリスト内の項目の位置を返します
Integerordinal
Enum 項目の値を String として返します
Stringvalues
例
Integer I = StatusCodeDELETE_FAILEDordinal() String S = MyEnumXname()
Enum についての詳細は「Enum 値」 (ページ 38)を参照してください
参照 Version 180 | Enum メソッド | 237
sObject メソッド
Apex sObject メソッド用語 sObjectはSalesforcecom プラットフォームデータベースに保存できるオブジェクトのことをいいます次の Apex sObject メソッドにはsObject 構造の説明に使用する一般的なクラスのほかすべての sObject と使用できるメソッドが含まれます
bull Schemabull sObjectbull sObject 定義結果bull 項目定義結果bull カスタム設定
Schema メソッド
次の表ではSchema の静的システムメソッドを示しています
説明戻り値の型引数名前
組織で定義された標準オブジェクトおよびカスタムオブ
MapltStringSchemaSObjectTypegt
getGlobalDescribe
ジェクトのすべての sObject名 (キー) のマップをsObjectトークン (値) に返します例MapltStringSchemaSObjectTypegt gd=SchemagetGlobalDescribe()
詳細は「すべての sObjectsへのアクセス」 (ページ 138)を参照してください
指定したオブジェクトに関連するカテゴリグループのリス
ListltSchemaDescribeDataCategoryGroupResultgt
StringListltsObjectNamesgt
describeDataCategoryGroups
トを返します次のsObjectNames のいずれかを指定できますbull KnowledgeArticleVersion
記事タイプに関連するカテゴリグループを取得します
bull Question 記事タイプに関連するカテゴリグループを取得します
参照 Version 180 | sObject メソッド | 238
説明戻り値の型引数名前
describeDataCategoryGroupsの使用についての詳細およびコード例は「sObject に関連するすべてのカテゴリのアクセス」を参照してください
記事および質問に関する詳細はSalesforcecomオンラインヘルプ「記事の管理」「Answers の概要」を参照してください
要求で指定されたオブジェクトのデータカテゴリ構造とと
ListltSchemaDescribeDataCategoryGroupStructureResultgt
pairstopCategoriesOnly
describeDataCategoryGroupStructures
もに使用できるカテゴリグループを返しますdescribeDataCategoryGroupStructuresの使用についての詳細およびコード例は「sObject に関連するすべてのカテゴリのアクセス」を参照してください
データカテゴリグループ構造定義の引数
describeDataCategoryGroupStructuresメソッドはデータカテゴリ構造とともに使用できるカテゴリグループを返します次にこのメソッドの引数を示します
説明戻り値の型名前
SchemaDataCategoryGroupSobjectTypePair を問い合わせる 1 つまたは複数のカテゴリグ
ListltSchemaDataCategoryGroupSobjectTypePairgtpairs
ループおよびオブジェクトを指定します指定されたオブジェクトの表示可能なデータカテゴリを取得します
カテゴリグループ表示の詳細はSalesforcecom オンラインヘルプの「カテゴリグループ表示設定の概要」を参照してください
trueを指定してオブジェクとを分類する上位表示カテゴリだけを返しますfalseを
BooleantopCategoriesOnly
指定して表示できるすべての親カテゴリおよび子カテゴリを返します両方の値はユーザのロールカテゴリグループ表示設定によって異なりますカテゴリグループ表示の
参照 Version 180 | Apex sObject メソッド | 239
説明戻り値の型名前
詳細はSalesforcecom オンラインヘルプの「カテゴリグループ表示設定の概要」を参照してください
SchemaDataCategoryGroupSobjectTypePair オブジェクト
SchemaDataCategoryGroupSobjectTypePair はカテゴリグループと関連オブジェクトを指定しますdescribeDataCategoryGroupStructuresメソッドで使用してこのオブジェクトに使用できるカテゴリを返します次の表はSchemaDataCategoryGroupSobjectTypePair のすべてのメソッドを示しています
説明戻り値の型引数名前
データカテゴリグループにアクセスするAPIで使用される一意の名前を返します
StringgetDataCategoryGroupName
データカテゴリグループに関連するオブジェクト名を返します
StringgetSobject
データカテゴリグループにアクセスするAPIで使用される一意の名前を指定します
StringsetDataCategoryGroupName
sObjectNameはデータカテゴリグループに関連するオブジェクト名です有効な値は次のとおりです
VoidString sObjectNamesetSobject
bull KnowledgeArticleVersion 記事タイプの場合
bull Question Answers の質問の場合
SchemaDescribeDataCategoryGroupResult オブジェクト
describeDataCategoryGroups メソッドは指定のオブジェクトに関連するカテゴリグループのリストを含むSchemaDescribeDataCategoryGroupResult オブジェクトを返します
次にデータカテゴリグループ定義結果オブジェクトのインスタンス化方法の例を示します
List ltStringgt objType = new ListltStringgt() objTypeadd(KnowledgeArticleVersion)objTypeadd(Question)
ListltSchemaDescribeDataCategoryGroupResultgt describeCategoryResult =SchemadescribeDataCategoryGroups(objType)
describeDataCategoryGroups の使用についての詳細およびコード例は「sObject に関連するすべてのカテゴリのアクセス」を参照してください
以下の表はデータカテゴリグループ定義結果の一部として利用可能なメソッドを示しています引数をとるメソッドはありません
参照 Version 180 | Apex sObject メソッド | 240
説明戻り値の型名前
データカテゴリグループの表示データカテゴリ数を返します
IntegergetCategoryCount
データカテゴリグループの説明を返しますStringgetDescription
Salesforcecomユーザインターフェースで使用するデータカテゴリグループのラベルを返します
StringgetLabel
データカテゴリグループにアクセスするAPIで使用される一意の名前を返します
StringgetName
データカテゴリグループに関連するオブジェクト名を返します
StringgetSobject
SchemaDescribeDataCategoryGroupStructureResult オブジェクト
describeDataCategoryGroupStructuresメソッドは指定したオブジェクトのカテゴリグループおよびカテゴリを含む SchemaDescribeDataCategoryGroupStructureResult オブジェクトのリストを返します
次にデータカテゴリグループ構造定義結果オブジェクトのインスタンス化方法の例を示します
List ltDataCategoryGroupSobjectTypePairgt pairs = new ListltDataCategoryGroupSobjectTypePairgt()
DataCategoryGroupSobjectTypePair pair1 = new DataCategoryGroupSobjectTypePair()pair1setSobject(KnowledgeArticleVersion) pair1setDataCategoryGroupName(Regions)
DataCategoryGroupSobjectTypePair pair2 = new DataCategoryGroupSobjectTypePair()pair2setSobject(Questions) pair2setDataCategoryGroupName(Regions)
pairsadd(pair1) pairsadd(pair2)
ListltSchemaDescribeDataCategoryGroupStructureResultgtresults =SchemadescribeDataCategoryGroupStructures(pairs true)
describeDataCategoryGroupStructuresの使用についての詳細およびコード例は「sObject に関連するすべてのカテゴリのアクセス」を参照してください
以下の表はデータカテゴリグループ構造定義結果の一部として利用可能なメソッドを示しています引数をとるメソッドはありません
説明戻り値の型名前
データカテゴリグループの説明を返しますStringgetDescription
Salesforcecomユーザインターフェースで使用するデータカテゴリグループのラベルを返します
StringgetLabel
データカテゴリグループにアクセスするAPIで使用される一意の名前を返します
StringgetName
データカテゴリグループに関連するオブジェクト名を返します
StringgetSobject
参照 Version 180 | Apex sObject メソッド | 241
説明戻り値の型名前
ユーザのカテゴリグループ表示設定に基づく上位表示カテゴリを含むSchemaDataCategory
ListltSchemaDataCategorygtgetTopCategories
オブジェクトを返しますカテゴリグループ表示の詳細はSalesforcecomオンラインヘルプの「カテゴリグループ表示設定の概要」を参照してください
SchemaDataCategory オブジェクト
SchemaDataCategory オブジェクトはカテゴリグループ内のカテゴリを示しますSchemaDataCategory オブジェクトは getTopCategoriesメソッドによって返されます次の表はSchemaDataCategory のすべてのメソッドを示しています引数をとるメソッドはありません
説明戻り値の型名前
データカテゴリの表示サブカテゴリを含む再帰オブジェクトを返します
ListltSchemaDataCategorygtgetChildCategories
Salesforcecomユーザインターフェースで使用するデータカテゴリのラベルを返します
StringgetLabel
データカテゴリにアクセスするAPIで使用される一意の名前を返します
StringgetName
sObject メソッド
sObject メソッドはすべてのインスタンスメソッドで取引先または連絡先などsObject の特定のインスタンスにコールされ操作します次にsObject のインスタンスメソッドを示します
説明戻り値の型引数名前
カスタムエラーメッセージでレコードをマークしDML 操作が行われないようにします
before insertトリガおよび before updateトリガの Triggernewにbefore deleteトリガ
VoidString errorMsgaddError
の Triggeroldに使用するとアプリケーションインターフェースにエラーメッセージが表示されます
「トリガ」 (ページ 65)および「トリガの例外」(ページ 77)を参照してください
Visualforce コントローラで使用すると生成されたメッセージがそのページのエラーのコレクションに追加されます詳細は『Visualforce DevelopersGuide』の「入力規則と標準コントローラ」を参照してください
参照 Version 180 | Apex sObject メソッド | 242
説明戻り値の型引数名前
指定したエラーメッセージをアプリケーションインターフェースのこのメソッドをコールする項目
VoidString errorMsgfieldaddError
に投入しDML 操作が行われないようにします例TriggernewmyField__CaddError(bad)
メモ
bull before insertトリガおよび before update
トリガの Triggernewにbefore deleteトリガのTriggeroldに使用するとアプリケーションインターフェースにエラーが表示されます
bull Visualforce コントローラで使用するとinputFieldコンポーネントが項目に結合される場合メッセージがコンポーネントに添付されます詳細は『Visualforce Developers Guide』の「入力規則と標準コントローラ」を参照してください
bull 項目識別子は実際に呼び出しオブジェクトではなくsObject が呼び出し元であるためこのメソッドは高度に専門化されます項目を使用してエラーの表示に使用する項目を識別します
bull このメソッドは今後のバージョンの Apex で変更される可能性があります
「トリガ」 (ページ 65)および「トリガの例外」(ページ 77)を参照してください
すべての項目値をクリアしますVoidclear
sObject レコードのコピーを作成します
オプションの opt_preserve_id引数は元のオブジェクトの ID を複製で保持するかまたは削除するかを指定します
sObject (同じデータ型)
Booleanopt_preserve_idBooleanopt_IsDeepClone
clone
オプションの opt_IsDeepClone引数はメソッドが sObject の完全コピーを作成するか単なる参照を作成するかを指定します
bull trueに設定するとメソッドは sObject の完全コピーを作成しますリレーション項目などsObject のすべての項目はメモリで複製されますその結果複製された sObject の項目に変更を行っても元の sObject は影響されません
bull falseに設定するとメソッドは元の sObjectへの参照を作成しますその結果複製された
参照 Version 180 | Apex sObject メソッド | 243
説明戻り値の型引数名前
sObject の項目に変更を行っても元の sObjectも影響を受けます
AccountNumberなどfieldNameで指定された項目の値を返します
詳細は「動的 SOQL」 (ページ140)を参照してください
オブジェクトString fieldNameget
項目トークン SchemasObjectField (例SchemaAccountAccountNumber) で指定された項目の値を返します
詳細は「動的 SOQL」 (ページ140)を参照してください
オブジェクトSchemasObjectFieldField
get
sObject の databaseDMLOptions オブジェクトを返します
詳細は「データベース DMLOptions メソッド(ページ 273)」を参照してください
DatabaseDMLOptionsgetOptions
fieldNameで指定された項目の値を返しますこのメソッドは主に動的 DML とともに使用して外部 ID の値にアクセスします
詳細は「動的 DML」 (ページ142)を参照してください
sObjectString fieldNamegetSObject
項目トークン SchemafieldName (例SchemaAccountMyExternalId) で指定された
sObjectSchemaSObjectFieldfieldName
getSObject
項目の値を返しますこのメソッドは主に動的DML とともに使用して外部 ID の値にアクセスします
詳細は「動的 DML」 (ページ142)を参照してください
fieldNameで指定された項目の値を返しますこのメソッドは主に動的 DML とともに使用して
sObject[]String fieldNamegetSObjects
子関係など関連オブジェクトの値にアクセスします
詳細は「動的 DML」 (ページ142)を参照してください
項目トークン SchemafieldName (例SchemaAccountContact) で指定された項目の
sObject[]SchemaSObjectTypefieldName
getSObjects
値を返しますこのメソッドは主に動的 DMLとともに使用して子関係など関連オブジェクトの値にアクセスします
参照 Version 180 | Apex sObject メソッド | 244
説明戻り値の型引数名前
詳細は「動的 DML」 (ページ142)を参照してください
この sObject のトークンを返しますこのメソッドは定義情報で使用されます
詳細は「Apex 定義情報について」 (ページ 135)を参照してください
SchemaSObjectTypegetSObjectType
fieldNameで指定された項目の値を設定し項目の以前の値を返します
詳細は「動的 SOQL」 (ページ140)を参照してください
オブジェクトString fieldNameObject value
put
項目トークン SchemasObjectField (例SchemaAccountAccountNumber) で指定された項目の値を設定し項目の以前の値を返します
詳細は「動的 SOQL」 (ページ140)を参照してください
オブジェクトSchemaSObjectFieldfieldName Objectvalue
put
fieldNameで指定された項目の値を設定しますこのメソッドは主に動的 DML で使用して外
sObjectString fieldNamesObject value
putSObject
部 ID の値に設定しますメソッドは項目の以前の値を返します
詳細は「動的 SOQL」 (ページ140)を参照してください
トークンSchemasObjectTypeで指定される項目の値を設定しますこのメソッドは主に動的
sObjectSchemasObjectTypefieldName sObjectvalue
putSObject
DML で使用して外部 ID の値に設定しますメソッドは項目の以前の値を返します
詳細は「動的 SOQL」 (ページ140)を参照してください
sObject の DMLOptions オブジェクトを設定します
詳細は「データベース DMLOptions メソッド(ページ 273)」を参照してください
VoiddatabaseDMLOptionsDMLOptions
setOptions
sObjects についての詳細は「sObject 型」 (ページ 30)を参照してください
sObject 定義結果メソッド
以下の表はsObject定義結果に利用可能なメソッドであるDescribeSObjectResultオブジェクトを示しています引数をとるメソッドはありません
参照 Version 180 | Apex sObject メソッド | 245