Apex-quick-guide

提供:Dev Guides
移動先:案内検索

Apex-概要

Apexとは何ですか?

Apexは、Salesforce.comによって開発された独自の言語です。 公式の定義によると、Apexは厳密に型指定されたオブジェクト指向プログラミング言語であり、開発者はForce.comプラットフォームサーバーでForce.com APIの呼び出しと併せてフローおよびトランザクション制御ステートメントを実行できます。

Javaのような構文を持ち、データベースストアドプロシージャのように動作します。 開発者は、ボタンクリック、関連レコードの更新、Visualforce *ページなど、ほとんどのシステムイベントにビジネスロジックを追加できます。Apex*コードは、Webサービスリクエストおよびオブジェクトのトリガーから開始できます。 Apexは、Performance Edition、Unlimited Edition、Enterprise Edition、およびDeveloper Editionに含まれています。

Apexコード実行シナリオ

言語としてのApexの機能

言語としてのApexの機能について説明しましょう-

統合された

Apexには、INSERT、UPDATE、DELETEなどのDML操作、およびDML例外処理のサポートが組み込まれています。 sObjectレコードのセットを返すインラインSOQLおよびSOSLクエリ処理をサポートしています。 sObject、SOQL、SOSLについては、今後の章で詳しく説明します。

Javaのような構文と使いやすい

Apexは、Javaのような構文を使用するため、使いやすいです。 たとえば、変数宣言、ループ構文、条件ステートメント。

データと強力に統合

Apexは、複数のクエリとDMLステートメントを一緒に実行するように設計されたデータに特化しています。 データベースで複数のトランザクションステートメントを発行します。

強く型付けされた

Apexは強く型付けされた言語です。 sObjectなどのスキーマオブジェクトへの直接参照を使用します。無効な参照は、削除されたり、データ型が間違っているとすぐに失敗します。

マルチテナント環境

Apexはマルチテナント環境で実行されます。 その結果、Apexランタイムエンジンは、ランナウェイコードを厳重に保護し、共有リソースの独占を防止するように設計されています。 制限に違反するコードは、わかりやすいエラーメッセージで失敗します。

自動的にアップグレードする

Apexは、Salesforceリリースの一部としてアップグレードされます。 手動でアップグレードする必要はありません。

簡単なテスト

Apexは、カバーされているコードの量やコードのどの部分がより効率的であるかを示すテスト結果など、単体テストの作成と実行の組み込みサポートを提供します。

開発者はいつApexを選択すべきですか?

Apexは、事前に構築された既存の機能を使用して複雑なビジネス機能を実装できない場合に使用する必要があります。 以下は、Apex over Salesforce設定を使用する必要がある場合です。

Apexアプリケーション

必要なときにApexを使用できます-

  • 他のシステムと統合してWebサービスを作成します。
  • メールブラストまたはメールセットアップ用のメールサービスを作成します。
  • 複数のオブジェクトに対して同時に複雑な検証を実行し、カスタム検証の実装も実行します。
  • 既存のワークフロー機能またはフローでサポートされていない複雑なビジネスプロセスを作成します。
  • データベースメソッドを使用してレコードを更新するようなカスタムトランザクションロジック(単一のレコードまたはオブジェクトだけでなく、トランザクション全体で発生するロジック)を作成します。
  • レコードが変更されたときに何らかのロジックを実行するか、トリガーを発生させた何らかのイベントがあるときに関連オブジェクトのレコードを変更します。

Apexの動作構造

次の図に示すように(参照:Salesforce開発者ドキュメント)、Apexは完全にオンデマンドで実行されますForce.comプラットフォーム

ApexコードのApexコンパイル

アクションの流れ

開発者がコードを保存するとき、およびエンドユーザーが以下に示すようにApexコードを呼び出すアクションを実行するとき、アクションの2つのシーケンスがあります-

開発者アクション

開発者がApexコードを作成してプラットフォームに保存すると、プラットフォームアプリケーションサーバーは最初にコードをApexランタイムインタープリターが理解できる一連の命令にコンパイルし、次にそれらの命令をメタデータとして保存します。

エンドユーザーアクション

エンドユーザーがボタンをクリックするかVisualforceページにアクセスしてApexの実行をトリガーすると、プラットフォームアプリケーションサーバーはメタデータからコンパイルされた命令を取得し、結果を返す前にランタイムインタープリターを介してそれらを送信します。 エンドユーザーは、標準のアプリケーションプラットフォーム要求と比較して、実行時間に違いがないことに気付きます。

ApexはSalesforce.comの専用言語であるため、一般的なプログラミング言語がサポートする機能の一部はサポートしていません。 以下は、Apexがサポートしていないいくつかの機能です-

  • ユーザーインターフェイスに要素を表示できません。
  • SFDCが提供する標準の機能を変更することはできません。また、標準の機能の実行を妨げることもできません。
  • 複数のスレッドを作成することも、他の言語でできるため不可能です。

Apex構文について

通常、Apexコードには、他のプログラミング言語で慣れ親しんでいる多くのものが含まれています。

可変宣言

厳密に型指定された言語として、Apexでデータ型を持つすべての変数を宣言する必要があります。 次のコード(下のスクリーンショット)に見られるように、lstAccは、アカウントのリストとしてデータ型で宣言されています。

SOQLクエリ

これは、Salesforceデータベースからデータを取得するために使用されます。 以下のスクリーンショットに示すクエリは、Accountオブジェクトからデータを取得しています。

ループ文

このループステートメントは、リストの繰り返し、または指定された回数のコードの繰り返しに使用されます。 以下のスクリーンショットに示されているコードでは、反復は記録の数と同じです。

フロー制御ステートメント

このコードでは、Ifステートメントがフロー制御に使用されます。 特定の条件に基づいて、特定のコードの実行を実行するか停止するかが決定されます。 たとえば、次のコードでは、リストが空であるか、レコードが含まれているかを確認しています。

DMLステートメント

データベース内のレコードに対してレコードの挿入、更新、アップサート、削除操作を実行します。 たとえば、次のコードは、新しいフィールド値でアカウントを更新するのに役立ちます。

以下は、Apexコードスニペットがどのように見えるかの例です。 このチュートリアルでは、これらすべてのApexプログラミングの概念をさらに学習します。

Apexサンプルコードの構文

Apex-環境

この章では、Salesforce Apex開発の環境を理解します。 Apex開発を行うためのSalesforceエディションがすでにセットアップされていることを前提としています。

SalesforceのSandboxまたはDeveloperエディションでApexコードを開発できます。 サンドボックス組織とは、データの変更や通常の機能を妨げるリスクを負うことなく、コードを記述してテストできる組織のコピーです。 標準的な産業慣行に従って、Sandboxでコードを開発してから、実稼働環境に展開する必要があります。

このチュートリアルでは、SalesforceのDeveloperエディションを使用します。 Developerエディションでは、Sandbox組織を作成するオプションはありません。 Sandbox機能は、Salesforceの他のエディションで使用できます。

展開プロセス

Apexコード開発ツール

すべてのエディションでは、次の3つのツールのいずれかを使用してコードを開発できます-

  • Force.com開発者コンソール
  • Force.com IDE
  • Salesforceユーザーインターフェースのコードエディター
  • 注-*シンプルで学習しやすいため、チュートリアル全体でコード実行の開発者コンソールを利用します。

Force.com開発者コンソール

開発者コンソールは、Salesforce組織でアプリケーションを作成、デバッグ、およびテストするために使用できるツールのコレクションを備えた統合開発環境です。

次の手順に従って、開発者コンソールを開きます-

ステップ1- [名前]→[開発者コンソール]に移動します

デベロッパーコンソールステップ1を開く

ステップ2- [開発者コンソール]をクリックすると、次のスクリーンショットのようにウィンドウが表示されます。

Opening Developer Console Step_2

以下は、開発者コンソールを使用して実行できるいくつかの操作です。

  • *コードの記述とコンパイル-*ソースコードエディターを使用してコードを記述できます。 トリガーまたはクラスを保存すると、コードは自動的にコンパイルされます。 コンパイルエラーが報告されます。
  • *デバッグ-*ソースコードエディタを使用してコードを書くことができます。 トリガーまたはクラスを保存すると、コードは自動的にコンパイルされます。 コンパイルエラーが報告されます。
  • *テスト-*デバッグログを表示し、デバッグに役立つチェックポイントを設定できます。
  • *パフォーマンスの確認-*組織内の特定のテストクラスまたはすべてのクラスのテストを実行でき、テスト結果を表示できます。 また、コードカバレッジを検査できます。
  • * SOQLクエリ-*デバッグログを調べて、パフォーマンスのボトルネックを見つけることができます。
  • *カラーコーディングとオートコンプリート-*ソースコードエディターは、コード要素を読みやすくするためにカラースキームを使用し、クラス名とメソッド名の自動補完を提供します。

開発者コンソールでコードを実行する

このチュートリアルで言及したすべてのコードスニペットは、開発者コンソールで実行する必要があります。 次の手順に従って、開発者コンソールで手順を実行します。

ステップ1 *- *login.salesforce.com を使用してSalesforce.comにログインします。 チュートリアルに記載されているコードスニペットをコピーします。 ここでは、次のサンプルコードを使用します。

String myString = 'MyString';
System.debug('Value of String Variable'+myString);

ログイン画面

  • ステップ2 *-開発者コンソールを開くには、以下に示すように[名前]→[開発者コンソール]をクリックし、[匿名で実行]をクリックします。

開発者コンソールステップ1でのコードの実行

開発者コンソールステップ2でのコードの実行

  • ステップ3 *-このステップでは、ウィンドウが表示され、そこにコードを貼り付けることができます。

開発者コンソールステップ3でのコードの実行

  • ステップ4 *-*実行*をクリックすると、デバッグログが開きます。 下に示すようにウィンドウにログが表示されたら、ログレコードをクリックします。

ログ記録

次に、以下に示すようにウィンドウに「USER」と入力すると、出力ウィンドウがデバッグウィンドウに表示されます。 この「USER」ステートメントは、出力のフィルタリングに使用されます。

開発者コンソールステップ4でのコードの実行

したがって、基本的に、このチュートリアルのコードスニペットを実行するには、上記のすべての手順を実行します。

Apex-例

エンタープライズアプリケーション開発の例

このチュートリアルでは、化学機器および加工会社向けのCRMアプリケーションを実装します。 この会社はサプライヤーと取引し、サービスを提供します。 チュートリアル全体でこの例に関連する小さなコードスニペットを作成して、すべての概念を詳細に理解します。

このチュートリアルのコードを実行するには、CustomerオブジェクトとInvoiceオブジェクトの2つのオブジェクトを作成する必要があります。 Salesforceでこれらのオブジェクトを作成する方法をすでに知っている場合は、以下の手順をスキップできます。 それ以外の場合は、以下のステップバイステップガイドに従ってください。

顧客オブジェクトの作成

最初にCustomerオブジェクトを設定します。

  • ステップ1 *-セットアップに移動し、次に示すように「オブジェクト」を検索します。 次に、下に示すように[オブジェクト]リンクをクリックします。

Customer Object Ceation Step1

Customer Object Ceation Step1-2

ステップ2 *-オブジェクトページが開いたら、以下に示すように、[ *Create New Object ]ボタンをクリックします。

Customer Object Ceation Step3

  • ステップ3 *-ボタンをクリックすると、新しいオブジェクト作成ページが表示され、以下に入力したようにすべてのオブジェクトの詳細を入力します。 オブジェクト名はCustomerである必要があります。 下のスクリーンショットに示すように、フィールドに情報を入力するだけで、他のデフォルトのものはそのままにしておく必要があります。

Customer Object Ceation Step4

情報を入力し、「保存」ボタンをクリックします-

Customer Object Ceation Step5

上記の手順に従って、Customerオブジェクトを正常に作成しました。

Customerオブジェクトのカスタムフィールドの作成

Customerオブジェクトが設定されたので、「アクティブ」フィールドを作成し、同様の手順に従って他のフィールドを作成できます。 フィールドの名前とAPI名がスクリーンショットに表示されます。

  • ステップ1 *-チェックボックスとしてデータ型の「アクティブ」という名前のフィールドを作成します。 [設定]に移動してクリックします。

Customer Custom Field Creation Step1

  • ステップ2 *-以下に示すように「オブジェクト」を検索してクリックします。

Customer Custom Field Creation Step2

  • ステップ3 *-オブジェクト「顧客」をクリックします。

Customer Custom Field Creation Step3

  • ステップ4 *-顧客オブジェクトリンクをクリックして、オブジェクトの詳細ページが表示されたら、[新規]ボタンをクリックします。

Customer Custom Field Creation Step4

  • ステップ5 *-次に、チェックボックスとしてデータ型を選択し、[次へ]をクリックします。

Customer Custom Field Creation Step5

  • ステップ6 *-以下に示すように、フィールド名とラベルを入力します。

Customer Custom Field Creation Step6

  • ステップ7 *-[表示]をクリックし、[次へ]をクリックします。

Customer Custom Field Creation Step7

  • ステップ8 *-「保存」をクリックします。

Customer Custom Field Creation Step8

上記の手順に従うと、カスタムフィールド「アクティブ」が作成されます。 残りのフィールドについては、上記のすべてのカスタムフィールド作成手順に従う必要があります。 これは、すべてのフィールドが作成された後の顧客オブジェクトの最終ビューです-

最終ビュー顧客オブジェクト

請求書オブジェクトの作成

  • ステップ1 *-[設定]に移動して[オブジェクト]を検索し、次に示すように[オブジェクト]リンクをクリックします。

請求書オブジェクト作成ステップ1

請求書オブジェクト作成ステップ2

  • ステップ2 *-オブジェクトページが開いたら、次に示すように[新しいオブジェクトの作成]ボタンをクリックします。

請求書オブジェクト作成ステップ3

  • ステップ3 *-ボタンをクリックすると、下のスクリーンショットに示すように、新しいオブジェクト作成ページが表示されます。 ここに詳細を入力する必要があります。 オブジェクト名は請求書である必要があります。 これは、このチュートリアルの前半でCustomerオブジェクトを作成した方法に似ています。

請求書オブジェクト作成ステップ4

  • ステップ4 *-以下に示すように情報を入力し、「保存」ボタンをクリックします。

請求書オブジェクト作成手順5

これらの手順に従うと、請求書オブジェクトが作成されます。

請求書オブジェクトのカスタムフィールドの作成

以下に示すように、請求書オブジェクトのフィールド説明を作成します-

  • ステップ1 *-セットアップに移動して、それをクリックします。

顧客オブジェクト作成ステップ1

  • ステップ2 *-以下に示すように「オブジェクト」を検索してクリックします。

Customer Object Creation Step1-2

  • ステップ3 *-「請求書」オブジェクトをクリックします。

Invoice Custom Field Creation Step3

そして、「新規」をクリックします。

請求書カスタムフィールド作成ステップ

  • ステップ4 *-テキストエリアとしてデータタイプを選択し、[次へ]ボタンをクリックします。

Invoice Custom Field Creation Step5

  • ステップ5 *-以下の情報を入力します。

Invoice Custom Field Creation Step6

  • ステップ6 *-[表示]、[次へ]の順にクリックします。

Invoice Custom Field Creation Step7

  • ステップ7 *-[保存]をクリックします。

Invoice Custom Field Creation Step8

同様に、Invoiceオブジェクトに他のフィールドを作成できます。

最終請求書オブジェクトビュー

これにより、このチュートリアルに必要なオブジェクトを作成しました。 これらのオブジェクトに基づいて、後続の章でさまざまな例を学習します。

Apex-データ型

データ型を理解する

Apex言語は厳密に型指定されているため、Apexのすべての変数は特定のデータ型で宣言されます。 すべての頂点変数は、最初はnullに初期化されます。 開発者は、適切な値が変数に割り当てられていることを確認することを常にお勧めします。 それ以外の場合、このような変数を使用すると、nullポインター例外または未処理の例外がスローされます。

Apexは次のデータ型をサポートしています-

  • プリミティブ(整数、倍精度、長整数、日付、日時、文字列、ID、またはブール)
  • コレクション(リスト、セット、およびマップ)(第6章で説明します)
  • sObject
  • 列挙型
  • クラス、オブジェクト、インターフェイス(第11章、12章、13章で説明します)

この章では、すべてのプリミティブデータ型、sObject、およびEnumを見ていきます。 コレクション、クラス、オブジェクト、インターフェースは、個別に学ぶべき重要なトピックなので、今後の章で検討します。

プリミティブデータ型

このセクションでは、Apexでサポートされるプリミティブデータ型について説明します。

整数

小数点を含まない32ビットの数値。 この値の範囲は-2,147,483,648から始まり、最大値は最大2,147,483,647です。

化学処理プラントのバイヤーに出荷する必要のあるバレルの量を格納する変数を宣言します。

Integer barrelNumbers = 1000;
system.debug(' value of barrelNumbers variable: '+barrelNumbers);
  • System.debug()*関数は変数の値を出力するため、これを使用してデバッグしたり、変数が現在保持している値を知ることができます。

上記のコードをデベロッパーコンソールに貼り付け、[実行]をクリックします。 ログが生成されると、変数「barrelNumbers」の値が1000として表示されます。

ブール値

この変数は、true、false、またはnullのいずれかです。 多くの場合、このタイプの変数は、特定の条件が設定されているかどうかを識別するためのプログラミングのフラグとして使用できます。

ブールのshipmentDispatchedがtrueに設定される場合、それは次のように宣言することができます-

Boolean shipmentDispatched;
shipmentDispatched = true;
System.debug('Value of shipmentDispatched '+shipmentDispatched);

Date

この変数タイプは日付を示します。 これは、日付ではなく時刻のみを保存できます。 時間とともに日付を保存するには、DateTimeの変数に保存する必要があります。

Date変数の動作を理解するには、次の例を検討してください。

//ShipmentDate can be stored when shipment is dispatched.
Date ShipmentDate = date.today();
System.debug('ShipmentDate '+ShipmentDate);

Long

これは、小数点のない64ビットの数値です。 これは、Integerが提供する値よりも広い範囲の値が必要な場合に使用されます。

会社の収益を保存する場合は、データ型をLongとして使用します。

Long companyRevenue = 21474838973344648L;
system.debug('companyRevenue'+companyRevenue);

対象

これは、Apexでサポートされている任意のデータ型として参照できます。 たとえば、クラス変数はそのクラスのオブジェクトにすることができ、sObjectジェネリック型もオブジェクトであり、Accountなどの同様に特定のオブジェクト型もオブジェクトです。

bject変数の機能を理解するには、次の例を検討してください。

Account objAccount = new Account (Name = 'Test Chemical');
system.debug('Account value'+objAccount);

-以下に示すように、事前定義されたクラスのオブジェクトも作成できます-

//Class Name: MyApexClass
MyApexClass classObj = new MyApexClass();

これは、クラス変数として使用されるクラスオブジェクトです。

ひも

文字列は、単一引用符で囲まれた文字のセットです。 文字数に制限はありません。 ここでは、ヒープサイズを使用して文字数を決定します。 これにより、Apexプログラムによるリソースの独占が抑制され、リソースが大きくなりすぎないようになります。

String companyName = 'Abc International';
System.debug('Value companyName variable'+companyName);

Time

この変数は、特定の時間を格納するために使用されます。 この変数は、常にシステムの静的メソッドで宣言する必要があります。

Blob

Blobは、オブジェクトとして保存されるバイナリデータのコレクションです。 これは、セールスフォースの添付ファイルを変数に保存するときに使用されます。 このデータ型は、添付ファイルを単一のオブジェクトに変換します。 BLOBを文字列に変換する場合は、同じためにtoStringメソッドとvalueOfメソッドを使用できます。

sObject

これはSalesforceの特別なデータ型です。 SQLのテーブルに似ており、SQLの列に似たフィールドが含まれています。 sObjectには、標準とカスタムの2つのタイプがあります。

たとえば、アカウントは標準のsObjectであり、他のユーザー定義オブジェクト(作成したCustomerオブジェクトなど)はカスタムsObjectです。

//Declaring an sObject variable of type Account
Account objAccount = new Account();

//Assignment of values to fields of sObjects
objAccount.Name = 'ABC Customer';
objAccount.Description = 'Test Account';
System.debug('objAccount variable value'+objAccount);

//Declaring an sObject for custom object APEX_Invoice_c
APEX_Customer_c objCustomer = new APEX_Customer_c();

//Assigning value to fields
objCustomer.APEX_Customer_Decscription_c = 'Test Customer';
System.debug('value objCustomer'+objCustomer);

Enum

Enumは、指定された識別子の有限セットの1つの値を格納する抽象データ型です。 キーワードEnumを使用して、Enumを定義できます。 Enumは、Salesforceの他のデータ型として使用できます。

あなたは、次のコードを実行することにより、化学化合物の可能な名前を宣言することができます-

//Declaring enum for Chemical Compounds
public enum Compounds {HCL, H2SO4, NACL, HG}
Compounds objC = Compounds.HCL;
System.debug('objC value: '+objC);

Apex-変数

JavaとApexは多くの点で似ています。 JavaとApexの変数宣言もまったく同じです。 ローカル変数の宣言方法を理解するために、いくつかの例を説明します。

String productName = 'HCL';
Integer i = 0;
Set<string> setOfProducts = new Set<string>();
Map<id, string> mapOfProductIdToName = new Map<id, string>();

すべての変数には値nullが割り当てられていることに注意してください。

変数の宣言

次のように文字列や整数のようなApexで変数を宣言することができます-

String strName = 'My String'; //String variable declaration
Integer myInteger = 1;        //Integer variable declaration
Boolean mtBoolean = true;     //Boolean variable declaration

頂点変数は大文字と小文字を区別しません

これは、変数 'm’が2回宣言されており、両方が同じものとして扱われるため、以下のコードはエラーをスローすることを意味します。

Integer m = 100;
for (Integer i = 0; i<10; i++) {
   integer m = 1;//This statement will throw an error as m is being declared
   again
   System.debug('This code will throw error');
}

変数の範囲

Apex変数は、コードで宣言された時点から有効です。 したがって、同じ変数をコードブロックで再定義することはできません。 また、メソッドで変数を宣言すると、その変数スコープはその特定のメソッドのみに制限されます。 ただし、クラス変数はクラス全体でアクセスできます。

//Declare variable Products
List<string> Products = new List<strings>();
Products.add('HCL');

//You cannot declare this variable in this code clock or sub code block again
//If you do so then it will throw the error as the previous variable in scope
//Below statement will throw error if declared in same code block
List<string> Products = new List<strings>();

Apex-文字列

Apexの文字列は、他のプログラミング言語と同様に、文字数制限のない任意の文字セットです。

String companyName = 'Abc International';
System.debug('Value companyName variable'+companyName);

文字列メソッド

Salesforceの文字列クラスには多くのメソッドがあります。 この章では、最も重要で頻繁に使用される文字列メソッドのいくつかを見ていきます。

含む

このメソッドは、指定された文字列に上記のサブストリングが含まれている場合にtrueを返します。

構文

public Boolean contains(String substring)

String myProductName1 = 'HCL';
String myProductName2 = 'NAHCL';
Boolean result = myProductName2.contains(myProductName1);
System.debug('O/p will be true as it contains the String and Output is:'+result);

等しい

このメソッドは、指定された文字列とメソッドで渡された文字列が同じ文字のバイナリシーケンスを持ち、それらがnullでない場合にtrueを返します。 この方法を使用して、SFDCレコードIDも比較できます。 このメソッドは大文字と小文字を区別します。

構文

public Boolean equals(Object string)

String myString1 = 'MyString';
String myString2 = 'MyString';
Boolean result = myString2.equals(myString1);
System.debug('Value of Result will be true as they are same and Result is:'+result);

equalsIgnoreCase

stringtoCompareに指定された文字列と同じ文字シーケンスがある場合、このメソッドはtrueを返します。 ただし、このメソッドは大文字と小文字を区別しません。

構文

public Boolean equalsIgnoreCase(String stringtoCompare)

次のコードは、文字列の文字とシーケンスが同じであるため、大文字と小文字の区別を無視してtrueを返します。

String myString1 = 'MySTRING';
String myString2 = 'MyString';
Boolean result = myString2.equalsIgnoreCase(myString1);
System.debug('Value of Result will be true as they are same and Result is:'+result);

削除する

このメソッドは、指定された文字列からstringToRemoveで提供される文字列を削除します。 これは、文字列から特定の文字を削除したいが、削除する文字の正確なインデックスを知らない場合に便利です。 このメソッドは大文字と小文字を区別し、同じ文字シーケンスが発生しても大文字と小文字が異なる場合は機能しません。

構文

public String remove(String stringToRemove)

String myString1 = 'This Is MyString Example';
String stringToRemove = 'MyString';
String result = myString1.remove(stringToRemove);
System.debug('Value of Result will be 'This Is Example' as we have removed the MyString
   and Result is :'+result);

removeEndIgnoreCase

このメソッドは、指定された文字列からstringToRemoveで提供された文字列を削除しますが、最後に発生した場合のみです。 このメソッドは大文字と小文字を区別しません。

構文

public String removeEndIgnoreCase(String stringToRemove)

String myString1 = 'This Is MyString EXAMPLE';
String stringToRemove = 'Example';
String result = myString1.removeEndIgnoreCase(stringToRemove);
System.debug('Value of Result will be 'This Is MyString' as we have removed the 'Example'
   and Result is :'+result);

startsWith

指定された文字列がメソッドで指定されたプレフィックスで始まる場合、このメソッドはtrueを返します。

構文

public Boolean startsWith(String prefix)

String myString1 = 'This Is MyString EXAMPLE';
String prefix = 'This';
Boolean result = myString1.startsWith(prefix);
System.debug(' This will return true as our String starts with string 'This' and the
   Result is :'+result);

Apex-配列

Apexの配列は、基本的にApexのリストと同じです。 内部データ構造とメソッドも同じであるため、配列とリストの間に論理的な区別はありませんが、配列構文はJavaのように伝統的ではありません。

以下は、製品の配列の表現です-

  • インデックス0 *-HCL
  • インデックス1 *-H2SO4
  • インデックス2 *-NACL
  • インデックス3 *-H2O
  • インデックス4 *-N2
  • インデックス5 *-U296

構文

<String> [] arrayOfProducts = new List<String>();

製品の名前を保存する必要があるとします。配列を使用して、以下に示すように製品名を保存します。 インデックスを指定することにより、特定の製品にアクセスできます。

//Defining array
String [] arrayOfProducts = new List<String>();

//Adding elements in Array
arrayOfProducts.add('HCL');
arrayOfProducts.add('H2SO4');
arrayOfProducts.add('NACL');
arrayOfProducts.add('H2O');
arrayOfProducts.add('N2');
arrayOfProducts.add('U296');

for (Integer i = 0; i<arrayOfProducts.size(); i++) {
  //This loop will print all the elements in array
   system.debug('Values In Array: '+arrayOfProducts[i]);
}

インデックスを使用して配列要素にアクセスする

以下に示すように、インデックスを使用して配列内の任意の要素にアクセスできます-

//Accessing the element in array
//We would access the element at Index 3
System.debug('Value at Index 3 is :'+arrayOfProducts[3]);

Apex-定数

他のプログラミング言語と同様に、定数は、宣言または値が割り当てられると値を変更しない変数です。

Apexでは、プログラム実行中に定数値を持つ変数を定義する場合に定数が使用されます。 Apex定数は、キーワード 'final’で宣言されます。

*CustomerOperationClass* クラスとその中の定数変数 *regularCustomerDiscount* を考慮してください-
public class CustomerOperationClass {
   static final Double regularCustomerDiscount = 0.1;
   static Double finalPrice = 0;

   public static Double provideDiscount (Integer price) {
     //calculate the discount
      finalPrice = price - price * regularCustomerDiscount;
      return finalPrice;
   }
}

上記のクラスの出力を表示するには、開発者コンソールの匿名ウィンドウで次のコードを実行する必要があります-

Double finalPrice = CustomerOperationClass.provideDiscount(100);
System.debug('finalPrice '+finalPrice);

Apex-意思決定

意思決定構造では、プログラマーが、プログラムによって評価またはテストされる1つ以上の条件を、条件が真であると判断された場合に実行されるステートメント、およびオプションで、条件は偽と判断されます。

この章では、Apexでの意思決定および条件文の基本的および高度な構造について学習します。 特定の条件が満たされているかどうかに応じて、実行のフローを制御するには意思決定が必要です。 以下は、ほとんどのプログラミング言語で見られる典型的な意思決定構造の一般的な形式です

意思決定

Sr.No. Statement & Description
1

if statement

ifステートメントは、ブール式とそれに続く1つ以上のステートメントで構成されます。

2

if…​else statement

ifステートメントの後にオプションの else ステートメントを続けることができます。これは、ブール式がfalseの場合に実行されます。

3

if…​elseif…​else statement

ifステートメントの後にオプションの else if …​ else ステートメントを続けることができます。これは、単一のif …​ else ifステートメントを使用してさまざまな条件をテストするのに非常に便利です。

4

nested if statement

1つの ifまたはelse if ステートメントを別の ifまたはelse if ステートメント内で使用できます。

Apex-ループ

ループは、特定のコードを目的の反復回数で繰り返す必要がある場合に使用されます。 Apexは、従来のforループおよびその他の高度なタイプのループをサポートしています。 この章では、Apexのループについて詳しく説明します。

ループステートメントは、ステートメントまたはステートメントのグループを複数回実行することを可能にし、ほとんどのプログラミング言語のループステートメントの一般的なものは次のとおりです-

ループアーキテクチャ

次の表に、Apexプログラミング言語のループ要件を処理するさまざまなループを示します。 詳細を確認するには、次のリンクをクリックしてください。

Sr.No. Loop Type & Description
1

for loop

このループは、一連のレコード内の各アイテムに対して一連のステートメントを実行します。

2

SOQL for loop

返されたSOQLクエリセットに対して一連のステートメントを直接実行します。

3

Java-like for loop

従来のJavaのような構文で一連のステートメントを実行します。

4

while loop

特定の条件が真の間、ステートメントまたはステートメントのグループを繰り返します。 ループ本体を実行する前に条件をテストします。

5

do…​while loop

whileステートメントと似ていますが、ループ本体の最後で条件をテストします。

Apex-コレクション

コレクションは、複数のレコードを保存できる変数の一種です。 たとえば、Listは複数のAccountオブジェクトのレコードを保存できます。 次に、すべてのコレクションタイプの詳細な概要を説明します。

リスト

リストには、プリミティブ、コレクション、sObject、ユーザー定義およびApexタイプで作成されたレコードをいくつでも含めることができます。 これはコレクションの最も重要なタイプの1つであり、Listで使用するために特別に調整されたいくつかのシステムメソッドもあります。 リストインデックスは常に0で始まります。 これは、Javaの配列と同義です。 リストは、キーワード「List」で宣言する必要があります。

以下は、プリミティブデータタイプ(文字列)のリスト、つまり都市のリストを含むリストです。

List<string> ListOfCities = new List<string>();
System.debug('Value Of ListOfCities'+ListOfCities);

listの初期値の宣言はオプションです。 ただし、ここで初期値を宣言します。 以下は同じことを示す例です。

List<string> ListOfStates = new List<string> {'NY', 'LA', 'LV'};
System.debug('Value ListOfStates'+ListOfStates);

アカウントのリスト(sObject)

List<account> AccountToDelete = new List<account> ();//This will be null
System.debug('Value AccountToDelete'+AccountToDelete);

ネストされたリストも宣言できます。 最大5つのレベルに移動できます。 これは多次元リストと呼ばれます。

これは整数のセットのリストです。

List<List<Set<Integer>>> myNestedList = new List<List<Set<Integer>>>();
System.debug('value myNestedList'+myNestedList);

リストには任意の数のレコードを含めることができますが、パフォーマンスの問題とリソースの独占を防ぐために、ヒープサイズに制限があります。

リストのメソッド

リストのサイズの計算、要素の追加などの機能を実現するためにプログラミング中に利用できるリストのメソッドがあります。

以下は、最も頻繁に使用されるいくつかの方法です-

  • サイズ()
  • add()
  • 取得する()
  • clear()
  • セット()

次の例は、これらすべての方法の使用法を示しています

//Initialize the List
List<string> ListOfStatesMethod = new List<string>();

//This statement would give null as output in Debug logs
System.debug('Value of List'+ ListOfStatesMethod);

//Add element to the list using add method
ListOfStatesMethod.add('New York');
ListOfStatesMethod.add('Ohio');

//This statement would give New York and Ohio as output in Debug logs
System.debug('Value of List with new States'+ ListOfStatesMethod);

//Get the element at the index 0
String StateAtFirstPosition = ListOfStatesMethod.get(0);

//This statement would give New York as output in Debug log
System.debug('Value of List at First Position'+ StateAtFirstPosition);

//set the element at 1 position
ListOfStatesMethod.set(0, 'LA');

//This statement would give output in Debug log
System.debug('Value of List with element set at First Position' + ListOfStatesMethod[0]);

//Remove all the elements in List
ListOfStatesMethod.clear();

//This statement would give output in Debug log
System.debug('Value of List'+ ListOfStatesMethod);

以下に示すように、リストを宣言するためにも配列表記を使用できますが、これはApexプログラミングの一般的な方法ではありません-

String [] ListOfStates = new List<string>();

Sets

セットは、複数の番号なしの一意のレコードを含むコレクションタイプです。 セットに重複レコードを含めることはできません。 リストと同様に、セットはネストできます。

会社が販売している製品のセットを定義します。

Set<string> ProductSet = new Set<string>{'Phenol', 'Benzene', 'H2SO4'};
System.debug('Value of ProductSet'+ProductSet);

セットのメソッド

セットは、以下に示すようにプログラミング中に利用できるメソッドをサポートします(上記の例を拡張しています)-

//Adds an element to the set
//Define set if not defined previously
Set<string> ProductSet = new Set<string>{'Phenol', 'Benzene', 'H2SO4'};
ProductSet.add('HCL');
System.debug('Set with New Value '+ProductSet);

//Removes an element from set
ProductSet.remove('HCL');
System.debug('Set with removed value '+ProductSet);

//Check whether set contains the particular element or not and returns true or false
ProductSet.contains('HCL');
System.debug('Value of Set with all values '+ProductSet);

Maps

これは、各値の一意のキーを含むキーと値のペアです。 キーと値の両方に任意のデータ型を使用できます。

次の例は、製品コードと製品名のマップを表しています。

//Initialize the Map
Map<string, string> ProductCodeToProductName = new Map<string, string>
{'1000'=>'HCL', '1001'=>'H2SO4'};

//This statement would give as output as key value pair in Debug log
System.debug('value of ProductCodeToProductName'+ProductCodeToProductName);

マップのメソッド

以下は、Mapで使用できるメソッドを示すいくつかの例です-

//Define a new map
Map<string, string> ProductCodeToProductName = new Map<string, string>();

//Insert a new key-value pair in the map where '1002' is key and 'Acetone' is value
ProductCodeToProductName.put('1002', 'Acetone');

//Insert a new key-value pair in the map where '1003' is key and 'Ketone' is value
ProductCodeToProductName.put('1003', 'Ketone');

//Assert that the map contains a specified key and respective value
System.assert(ProductCodeToProductName.containsKey('1002'));
System.debug('If output is true then Map contains the key and output is:'
   + ProductCodeToProductName.containsKey('1002'));

//Retrieves a value, given a particular key
String value = ProductCodeToProductName.get('1002');
System.debug('Value at the Specified key using get function: '+value);

//Return a set that contains all of the keys in the map
Set SetOfKeys = ProductCodeToProductName.keySet();
System.debug('Value of Set with Keys '+SetOfKeys);

マップ値は順序付けられていない可能性があるため、値が格納されている順序に依存してはならず、常にキーを使用してマップにアクセスしようとします。 マップ値はヌルにすることができます。 Stringを宣言するときのマップキーでは大文字と小文字が区別されます。たとえば、ABCとabcは異なるキーと見なされ、一意として扱われます。

Apex-クラス

クラスとは何ですか?

クラスは、オブジェクトが作成されるテンプレートまたはブループリントです。 オブジェクトはクラスのインスタンスです。 これは、クラスの標準定義です。 ApexクラスはJavaクラスに似ています。

たとえば、 InvoiceProcessor クラスは、請求書で実行できるすべてのメソッドとアクションを含むクラスを記述します。 このクラスのインスタンスを作成すると、現在コンテキストにある単一の請求書を表します。

クラスを作成する

開発者コンソール、Force.com Eclipse IDE、およびApexクラス詳細ページからもApexでクラスを作成できます。

開発者コンソールから

開発者コンソールからApexクラスを作成するには、次の手順に従います-

  • ステップ1 *-名前に移動し、開発者コンソールをクリックします。
  • ステップ2 *-[ファイル]⇒[新規]をクリックして、Apexクラスをクリックします。

クラスの作成

Force.com IDEから

Force.com IDEからクラスを作成するには、次の手順に従います-

  • ステップ1 *-Force.com Eclipse IDEを開きます
  • ステップ2 *-[ファイル]⇒[新規]⇒[Apexクラス]をクリックして、新しいプロジェクトを作成します。
  • ステップ3 *-クラスの名前を指定し、[OK]をクリックします。

これが完了すると、新しいクラスが作成されます。

Apexクラスの詳細ページから

Apexクラスの詳細ページからクラスを作成するには、次の手順に従います-

  • ステップ1 *-[名前]⇒[設定]をクリックします。
  • ステップ2 *-「頂点クラス」を検索し、リンクをクリックします。 Apexクラスの詳細ページが開きます。

詳細ページステップ1からApexクラスを作成

  • ステップ3 *-「新規」をクリックし、クラスの名前を入力して、「保存」をクリックします。

詳細ページステップ2からApexクラスを作成

Apexクラス構造

以下は、Apexクラス定義のサンプル構造です。

構文

private | public | global
[virtual | abstract | with sharing | without sharing]
class ClassName [implements InterfaceNameList] [extends ClassName] {
  //Classs Body
}

この定義では、アクセス修飾子、共有モード、クラス名、クラス本体の組み合わせを使用します。 これらすべてのオプションをさらに詳しく見ていきます。

以下は、Apexクラス定義のサンプル構造です-

public class MySampleApexClass {      //Class definition and body
   public static Integer myValue = 0; //Class Member variable
   public static String myString = '';//Class Member variable

   public static Integer getCalculatedValue () {
  //Method definition and body
  //do some calculation
      myValue = myValue+10;
      return myValue;
   }
}

アクセス修飾子

非公開

アクセス修飾子を「Private」として宣言すると、このクラスはローカルでのみ認識され、特定の部分以外ではこのクラスにアクセスできません。 デフォルトでは、クラスにはこの修飾子があります。

パブリック

クラスを「パブリック」として宣言する場合、このことは、このクラスが組織および定義済みの名前空間にアクセス可能であることを意味します。 通常、ほとんどのApexクラスはこのキーワードで定義されます。

グローバル

クラスを「グローバル」として宣言すると、組織に関係なく、すべての頂点コードからアクセスできます。 Webサービスキーワードでメソッドが定義されている場合、グローバルキーワードで包含クラスを宣言する必要があります。

共有モード

次に、さまざまな共有モードについて説明します。

共有あり

これは、SalesforceのApexクラスの特別な機能です。 「With Sharing」キーワードを使用してクラスを指定すると、次の意味があります。クラスが実行されると、ユーザーのアクセス設定とプロファイル許可が尊重されます。 ユーザーのアクションにより30レコードのレコード更新がトリガーされたが、ユーザーがアクセスできるのは20レコードのみで、10レコードにアクセスできないとします。 次に、クラスがレコードを更新するアクションを実行している場合、ユーザーがアクセスできる20個のレコードのみが更新され、残りの10個のレコードは更新されません。 これは、ユーザーモードとも呼ばれます。

共有なし

ユーザーが30のうち10のレコードにアクセスできない場合でも、クラスがシステムモードで実行されているため、30のレコードすべてが更新されます。つまり、キーワードを共有なしで定義されています。 これはシステムモードと呼ばれます。

バーチャル

「仮想」キーワードを使用する場合、このクラスを拡張でき、オーバーライドが許可されることを示します。 メソッドをオーバーライドする必要がある場合、クラスはvirtualキーワードで宣言する必要があります。

抽象

クラスを 'abstract’として宣言すると、メソッドのシグネチャのみが含まれ、実際の実装は含まれません。

クラス変数

構文

[public | private | protected | global] [final] [static] data_type
variable_name [= value]

上記の構文では-

  • 変数のデータ型と変数名は必須です
  • アクセス修飾子と値はオプションです。

public static final Integer myvalue;

Apex-メソッド

クラスメソッド

Apexのクラスメソッドには、パブリックまたは保護の2つの修飾子があります。 メソッドには戻り型が必須であり、メソッドが何も返さない場合は、戻り型としてvoidを指定する必要があります。 さらに、メソッドにはBodyも必要です。

構文

[public | private | protected | global]
[override]
[static]

return_data_type method_name (input parameters) {
  //Method body goes here
}

構文の説明

角括弧内に記載されているパラメータはオプションです。 ただし、次のコンポーネントが不可欠です-

  • return_data_type
  • method_name

クラスメソッドのアクセス修飾子

アクセス修飾子を使用して、クラスメソッドのアクセスレベルを指定できます。 たとえば、パブリックメソッドは、クラス内およびクラス外のどこからでもアクセスできます。 プライベートメソッドは、クラス内でのみアクセス可能です。 グローバルは、すべてのApexクラスからアクセス可能であり、他のapexクラスからアクセス可能なWebサービスメソッドとして公開できます。

//Method definition and body
public static Integer getCalculatedValue () {

  //do some calculation
   myValue = myValue+10;
   return myValue;
}

このメソッドの戻り値の型は整数であり、パラメーターを取りません。

メソッドは、次の例に示すようにパラメータを持つことができます-

//Method definition and body, this method takes parameter price which will then be used
//in method.

public static Integer getCalculatedValueViaPrice (Decimal price) {
  //do some calculation
   myValue = myValue+price;
   return myValue;
}

クラスコンストラクター

コンストラクターは、オブジェクトがクラスブループリントから作成されたときに呼び出されるコードです。 クラス名と同じ名前です。

デフォルトでは引数なしのコンストラクタが呼び出されるため、すべてのクラスにコンストラクタを定義する必要はありません。 コンストラクターは、変数の初期化、またはクラスの初期化時にプロセスを実行するときに役立ちます。 たとえば、クラスが呼び出されたときに、特定の整数変数に値を0として割り当てたいとします。

//Class definition and body
public class MySampleApexClass2 {
   public static Double myValue;  //Class Member variable
   public static String myString; //Class Member variable

   public MySampleApexClass2 () {
      myValue = 100;//initialized variable when class is called
   }

   public static Double getCalculatedValue () {//Method definition and body
     //do some calculation
      myValue = myValue+10;
      return myValue;
   }

   public static Double getCalculatedValueViaPrice (Decimal price) {
     //Method definition and body
     //do some calculation
      myValue = myValue+price;//Final Price would be 100+100=200.00
      return myValue;
   }
}

コンストラクターを介してクラスのメソッドを呼び出すこともできます。 これは、視覚フォースコントローラー用にApexをプログラミングするときに便利です。 クラスオブジェクトが作成されると、次に示すようにコンストラクタが呼び出されます-

//Class and constructor has been instantiated
MySampleApexClass2 objClass = new MySampleApexClass2();
Double FinalPrice = MySampleApexClass2.getCalculatedValueViaPrice(100);
System.debug('FinalPrice: '+FinalPrice);

オーバーロードコンストラクター

コンストラクターはオーバーロードできます。つまり、クラスは異なるパラメーターで定義された複数のコンストラクターを持つことができます。

public class MySampleApexClass3 { //Class definition and body
   public static Double myValue;  //Class Member variable
   public static String myString; //Class Member variable

   public MySampleApexClass3 () {
      myValue = 100;//initialized variable when class is called
      System.debug('myValue variable with no Overaloading'+myValue);
   }

   public MySampleApexClass3 (Integer newPrice) {//Overloaded constructor
      myValue = newPrice;//initialized variable when class is called
      System.debug('myValue variable with Overaloading'+myValue);
   }

      public static Double getCalculatedValue () {//Method definition and body
     //do some calculation
      myValue = myValue+10;
      return myValue;
   }

   public static Double getCalculatedValueViaPrice (Decimal price) {
     //Method definition and body
     //do some calculation
      myValue = myValue+price;
      return myValue;
   }
}

前の例で実行したように、このクラスを実行できます。

//Developer Console Code
MySampleApexClass3 objClass = new MySampleApexClass3();
Double FinalPrice = MySampleApexClass3.getCalculatedValueViaPrice(100);
System.debug('FinalPrice: '+FinalPrice);

Apex-オブジェクト

クラスのインスタンスはオブジェクトと呼ばれます。 Salesforceの観点では、オブジェクトはクラスにすることも、sObjectのオブジェクトを作成することもできます。

クラスからのオブジェクト作成

Javaまたは他のオブジェクト指向プログラミング言語で行ったように、クラスのオブジェクトを作成できます。

以下はMyClassと呼ばれるクラスの例です-

//Sample Class Example
public class MyClass {
   Integer myInteger = 10;

   public void myMethod (Integer multiplier) {
      Integer multiplicationResult;
      multiplicationResult = multiplier*myInteger;
      System.debug('Multiplication is '+multiplicationResult);
   }
}

これはインスタンスクラスです。つまり、このクラスの変数またはメソッドを呼び出したりアクセスしたりするには、このクラスのインスタンスを作成する必要があります。その後、すべての操作を実行できます。

//Object Creation
//Creating an object of class
MyClass objClass = new MyClass();

//Calling Class method using Class instance
objClass.myMethod(100);

オブジェクトの作成

sObjectは、データを保存するSalesforceのオブジェクトです。 たとえば、アカウント、連絡先などはカスタムオブジェクトです。 これらのsObjectのオブジェクトインスタンスを作成できます。

以下はsObjectの初期化の例であり、ドット表記を使用して特定のオブジェクトのフィールドにアクセスし、フィールドに値を割り当てる方法を示しています。

//Execute the below code in Developer console by simply pasting it
//Standard Object Initialization for Account sObject
Account objAccount = new Account();//Object initialization
objAccount.Name = 'Testr Account';//Assigning the value to field Name of Account
objAccount.Description = 'Test Account';
insert objAccount;//Creating record using DML
System.debug('Records Has been created '+objAccount);

//Custom sObject initialization and assignment of values to field
APEX_Customer_c objCustomer = new APEX_Customer_c ();
objCustomer.Name = 'ABC Customer';
objCustomer.APEX_Customer_Decscription_c = 'Test Description';
insert objCustomer;
System.debug('Records Has been created '+objCustomer);

静的初期化

静的メソッドと変数は、クラスがロードされるときに一度だけ初期化されます。 静的変数は、Visualforceページのビューステートの一部として送信されません。

以下は、静的メソッドと静的変数の例です。

//Sample Class Example with Static Method
public class MyStaticClass {
   Static Integer myInteger = 10;

   public static void myMethod (Integer multiplier) {
      Integer multiplicationResult;
      multiplicationResult = multiplier * myInteger;
      System.debug('Multiplication is '+multiplicationResult);
   }
}

//Calling the Class Method using Class Name and not using the instance object
MyStaticClass.myMethod(100);

静的変数の使用

静的変数は、クラスがロードされたときに1回だけインスタンス化され、この現象を使用してトリガーの再帰を回避できます。 静的変数の値は同じ実行コンテキスト内で同じになり、実行中のクラス、トリガー、またはコードはそれを参照して再帰を防ぐことができます。

Apex-インターフェース

インターフェースは、メソッドが実装されていないApexクラスのようなものです。 メソッドシグネチャのみが含まれますが、各メソッドの本文は空です。 インターフェイスを使用するには、別のクラスが、インターフェイスに含まれるすべてのメソッドの本体を提供することにより、インターフェイスを実装する必要があります。

インターフェイスは、主にコードの抽象化レイヤーを提供するために使用されます。 メソッドの宣言から実装を分離します。

化学会社の例を見てみましょう。 プレミアムと通常の顧客に割引を提供する必要があり、両方の割引が異なると仮定します。

*DiscountProcessor* というインターフェイスを作成します。
//Interface
public interface DiscountProcessor {
   Double percentageDiscountTobeApplied();//method signature only
}

//Premium Customer Class
public class PremiumCustomer implements DiscountProcessor {

  //Method Call
   public Double percentageDiscountTobeApplied () {

     //For Premium customer, discount should be 30%
      return 0.30;
   }
}

//Normal Customer Class
public class NormalCustomer implements DiscountProcessor {

  //Method Call
   public Double percentageDiscountTobeApplied () {

     //For Premium customer, discount should be 10%
      return 0.10;
   }
}

インターフェイスを実装する場合、そのインターフェイスのメソッドを実装することが必須です。 Interfaceメソッドを実装しないと、エラーがスローされます。 開発者にメソッドの実装を必須にする場合は、インターフェイスを使用する必要があります。

Apexの一括処理用の標準Salesforceインターフェイス

SFDCには、Database.Batchable、Schedulableなどの標準インターフェイスがあります。 たとえば、Database.Batchableインターフェイスを実装する場合、インターフェイスで定義されている3つのメソッド(Start、Execute、およびFinish)を実装する必要があります。

以下は、標準のSalesforceが提供するDatabase.Batchableインターフェースの例で、バッチステータスでユーザーにメールを送信します。 このインターフェイスには、Start、Execute、Finishの3つのメソッドがあります。 このインターフェイスを使用して、Batchable機能を実装できます。また、BatchableContext変数も提供します。この変数を使用して、実行中のバッチに関する詳細情報を取得し、他の機能を実行できます。

global class CustomerProessingBatch implements Database.Batchable<sobject7>,
Schedulable {
  //Add here your email address
   global String [] email = new String[] {'[email protected]'};

  //Start Method
   global Database.Querylocator start (Database.BatchableContext BC) {

     //This is the Query which will determine the scope of Records and fetching the same
      return Database.getQueryLocator('Select id, Name, APEX_Customer_Status__c,
         APEX_Customer_Decscription__c From APEX_Customer__c WHERE createdDate = today
         && APEX_Active__c = true');
   }

  //Execute method
   global void execute (Database.BatchableContext BC, List<sobject> scope) {
      List<apex_customer__c> customerList = new List<apex_customer__c>();
      List<apex_customer__c> updtaedCustomerList = new List<apex_customer__c>();

      for (sObject objScope: scope) {
        //type casting from generic sOject to APEX_Customer__c
         APEX_Customer__c newObjScope = (APEX_Customer__c)objScope ;
         newObjScope.APEX_Customer_Decscription__c = 'Updated Via Batch Job';
         newObjScope.APEX_Customer_Status__c = 'Processed';

        //Add records to the List
         updtaedCustomerList.add(newObjScope);
      }

     //Check if List is empty or not
      if (updtaedCustomerList != null && updtaedCustomerList.size()>0) {

        //Update the Records
         Database.update(updtaedCustomerList); System.debug('List Size
            '+updtaedCustomerList.size());
      }
   }

  //Finish Method
   global void finish(Database.BatchableContext BC) {
      Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();

     //get the job Id
      AsyncApexJob a = [Select a.TotalJobItems, a.Status, a.NumberOfErrors,
      a.JobType, a.JobItemsProcessed, a.ExtendedStatus, a.CreatedById,
      a.CompletedDate From AsyncApexJob a WHERE id = :BC.getJobId()];
      System.debug('$$$ Jobid is'+BC.getJobId());

     //below code will send an email to User about the status
      mail.setToAddresses(email);

     //Add here your email address
      mail.setReplyTo('[email protected]');
      mail.setSenderDisplayName('Apex Batch Processing Module');
      mail.setSubject('Batch Processing '+a.Status);
      mail.setPlainTextBody('The Batch Apex job processed
         '+a.TotalJobItems+'batches with '+a.NumberOfErrors+'failures'+'Job Item
         processed are'+a.JobItemsProcessed);
      Messaging.sendEmail(new Messaging.Singleemailmessage [] {mail});
   }

  //Scheduler Method to scedule the class
   global void execute(SchedulableContext sc) {
      CustomerProessingBatch conInstance = new CustomerProessingBatch();
      database.executebatch(conInstance,100);
   }
}

このクラスを実行するには、開発者コンソールで以下のコードを実行する必要があります。

CustomerProessingBatch objBatch = new CustomerProessingBatch ();
Database.executeBatch(objBatch);

Apex-DML

この章では、Salesforceでさまざまなデータベース変更機能を実行する方法について説明します。 機能を実行できる2つのコメントがあります。

DMLステートメント

DMLは、挿入、更新、削除、アップサート、レコードの復元、レコードのマージ、またはリードの変換操作を実行するために実行されるアクションです。

DMLはApexで最も重要な部分の1つです。ほとんどすべてのビジネスケースがデータベースの変更と修正を伴うためです。

データベースメソッド

DMLステートメントを使用して実行できるすべての操作は、データベースメソッドを使用しても実行できます。 データベースメソッドは、DML操作の実行に使用できるシステムメソッドです。 データベースメソッドは、DMLステートメントに比べて柔軟性が高くなります。

この章では、DMLステートメントを使用した最初のアプローチについて説明します。 後続の章でデータベースメソッドを見ていきます。

DMLステートメント

ここで、化学品の供給会社の例をもう一度考えてみましょう。 請求書レコードには、ステータス、支払額、残額、次回支払日、請求書番号などのフィールドがあります。 今日作成され、ステータスが「保留中」の請求書は、「支払済み」に更新する必要があります。

挿入操作

挿入操作は、データベースに新しいレコードを作成するために使用されます。 Insert DMLステートメントを使用して、標準オブジェクトまたはカスタムオブジェクトのレコードを作成できます。

新しい顧客の注文に対して毎日新しい請求書が生成されるため、APEX_Invoice__cオブジェクトに新しいレコードを作成できます。 最初に顧客レコードを作成してから、その新しい顧客レコードの請求書レコードを作成できます。

//fetch the invoices created today, Note, you must have at least one invoice
//created today

List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c,
   createdDate FROM APEX_Invoice__c WHERE createdDate = today];

//create List to hold the updated invoice records
List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>();
APEX_Customer__c objCust = new APEX_Customer__C();
objCust.Name = 'Test ABC';

//DML for Inserting the new Customer Records
insert objCust;
for (APEX_Invoice__c objInvoice: invoiceList) {
   if (objInvoice.APEX_Status__c == 'Pending') {
      objInvoice.APEX_Status__c = 'Paid';
      updatedInvoiceList.add(objInvoice);
   }
}

//DML Statement to update the invoice status
update updatedInvoiceList;

//Prints the value of updated invoices
System.debug('List has been updated and updated values are' + updatedInvoiceList);

//Inserting the New Records using insert DML statement
APEX_Invoice__c objNewInvoice = new APEX_Invoice__c();
objNewInvoice.APEX_Status__c = 'Pending';
objNewInvoice.APEX_Amount_Paid__c = 1000;
objNewInvoice.APEX_Customer__c = objCust.id;

//DML which is creating the new Invoice record which will be linked with newly
//created Customer record
insert objNewInvoice;
System.debug('New Invoice Id is '+objNewInvoice.id+' and the Invoice Number is'
   + objNewInvoice.Name);

更新操作

更新操作は、既存のレコードの更新を実行することです。 この例では、既存の請求書レコードのステータスフィールドを「支払い済み」に更新します。

//Update Statement Example for updating the invoice status. You have to create
and Invoice records before executing this code. This program is updating the
record which is at index 0th position of the List.

//First, fetch the invoice created today
List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c,
createdDate FROM APEX_Invoice__c];
List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>();

//Update the first record in the List
invoiceList[0].APEX_Status__c = 'Pending';
updatedInvoiceList.add(invoiceList[0]);

//DML Statement to update the invoice status
update updatedInvoiceList;

//Prints the value of updated invoices
System.debug('List has been updated and updated values of records are'
   + updatedInvoiceList[0]);

アップサート操作

更新挿入操作は、更新操作を実行するために使用され、更新するレコードがデータベースに存在しない場合は、新しいレコードも作成します。

Customerオブジェクトの顧客レコードを更新する必要があるとします。 既存の顧客レコードが既に存在する場合は更新し、そうでない場合は新しいレコードを作成します。 これは、フィールドAPEX_External_Id__cの値に基づきます。 このフィールドは、レコードがすでに存在するかどうかを識別するためのフィールドになります。

-このコードを実行する前に、外部IDフィールドの値を「12341」としてCustomerオブジェクトにレコードを作成し、次に示すコードを実行してください-

//Example for upserting the Customer records
List<apex_customer__c> CustomerList = new List<apex_customer__c>();
for (Integer i = 0; i < 10; i++) {
   apex_customer__c objcust=new apex_customer__c(name = 'Test' +i,
   apex_external_id__c='1234' +i);
   customerlist.add(objcust);
}//Upserting the Customer Records

upsert CustomerList;

System.debug('Code iterated for 10 times and created 9 records as one record with
   External Id 12341 is already present');

for (APEX_Customer_c objCustomer: CustomerList) {
   if (objCustomer.APEX_External_Id_c == '12341') {
      system.debug('The Record which is already present is '+objCustomer);
   }
}

削除操作

Delete DMLを使用して削除操作を実行できます。

この場合、テスト目的で作成された請求書、つまり「Test」という名前を含む請求書を削除します。

このスニペットは、クラスを作成せずに開発者コンソールからも実行できます。

//fetch the invoice created today
List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c,
createdDate FROM APEX_Invoice__c WHERE createdDate = today];
List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>();
APEX_Customer__c objCust = new APEX_Customer__C();
objCust.Name = 'Test';

//Inserting the Customer Records
insert objCust;
for (APEX_Invoice__c objInvoice: invoiceList) {
   if (objInvoice.APEX_Status__c == 'Pending') {
      objInvoice.APEX_Status__c = 'Paid';
      updatedInvoiceList.add(objInvoice);
   }
}

//DML Statement to update the invoice status
update updatedInvoiceList;

//Prints the value of updated invoices
System.debug('List has been updated and updated values are' + updatedInvoiceList);

//Inserting the New Records using insert DML statement
APEX_Invoice__c objNewInvoice = new APEX_Invoice__c();
objNewInvoice.APEX_Status__c = 'Pending';
objNewInvoice.APEX_Amount_Paid__c = 1000;
objNewInvoice.APEX_Customer__c = objCust.id;

//DML which is creating the new record
insert objNewInvoice;
System.debug('New Invoice Id is' + objNewInvoice.id);

//Deleting the Test invoices from Database
//fetch the invoices which are created for Testing, Select name which Customer Name
//is Test.
List<apex_invoice__c> invoiceListToDelete = [SELECT id FROM APEX_Invoice__c
   WHERE APEX_Customer__r.Name = 'Test'];

//DML Statement to delete the Invoices
delete invoiceListToDelete;
System.debug('Success, '+invoiceListToDelete.size()+' Records has been deleted');

元に戻す操作

削除され、ごみ箱にあるレコードの削除を取り消すことができます。 削除されたレコードが持つすべての関係も復元されます。

前の例で削除されたレコードを復元する必要があるとします。 これは、次の例を使用して実現できます。 前の例のコードは、この例のために変更されています。

//fetch the invoice created today
List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c,
createdDate FROM APEX_Invoice__c WHERE createdDate = today];
List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>();
APEX_Customer__c objCust = new APEX_Customer__C();
objCust.Name = 'Test';

//Inserting the Customer Records
insert objCust;
for (APEX_Invoice__c objInvoice: invoiceList) {
   if (objInvoice.APEX_Status__c == 'Pending') {
      objInvoice.APEX_Status__c = 'Paid';
      updatedInvoiceList.add(objInvoice);
   }
}

//DML Statement to update the invoice status
update updatedInvoiceList;

//Prints the value of updated invoices
System.debug('List has been updated and updated values are' + updatedInvoiceList);

//Inserting the New Records using insert DML statement
APEX_Invoice__c objNewInvoice = new APEX_Invoice__c();
objNewInvoice.APEX_Status__c = 'Pending';
objNewInvoice.APEX_Amount_Paid__c = 1000;
objNewInvoice.APEX_Customer__c = objCust.id;

//DML which is creating the new record
insert objNewInvoice;
System.debug('New Invoice Id is '+objNewInvoice.id);

//Deleting the Test invoices from Database
//fetch the invoices which are created for Testing, Select name which Customer Name
//is Test.
List<apex_invoice__c> invoiceListToDelete = [SELECT id FROM APEX_Invoice__c
   WHERE APEX_Customer__r.Name = 'Test'];

//DML Statement to delete the Invoices
delete invoiceListToDelete;
system.debug('Deleted Record Count is ' + invoiceListToDelete.size());
System.debug('Success, '+invoiceListToDelete.size() + 'Records has been deleted');

//Restore the deleted records using undelete statement
undelete invoiceListToDelete;
System.debug('Undeleted Record count is '+invoiceListToDelete.size()+'. This should
   be same as Deleted Record count');

Apex-データベースメソッド

データベースクラスメソッドは、挿入、更新などのDMLステートメントよりも柔軟なDMLステートメントを操作する別の方法です。

データベースメソッドとDMLステートメントの違い

DML Statements Database Methods
Partial Update is not allowed. For example, if you have 20 records in list, then either all the records will be updated or none. Partial update is allowed. You can specify the Parameter in Database method as true or false, true to allow the partial update and false for not allowing the same.
You cannot get the list of success and failed records. You can get the list of success and failed records as we have seen in the example.
Example − insert listName Example − Database.insert(listName, False), where false indicate that partial update is not allowed.

挿入操作

データベースメソッドを介して新しいレコードを挿入することも非常に簡単で柔軟です。 DMLステートメントを使用して新しいレコードを挿入した前のシナリオを考えてみましょう。 データベースメソッドを使用して同じものを挿入します。

//Insert Operation Using Database methods
//Insert Customer Records First using simple DML Statement. This Customer Record will be
//used when we will create Invoice Records
APEX_Customer__c objCust = new APEX_Customer__C();
objCust.Name = 'Test';
insert objCust;//Inserting the Customer Records

//Insert Operation Using Database methods
APEX_Invoice__c objNewInvoice = new APEX_Invoice__c();
List<apex_invoice__c> InvoiceListToInsert = new List<apex_invoice__c>();
objNewInvoice.APEX_Status__c = 'Pending';
objNewInvoice.APEX_Customer__c = objCust.id;
objNewInvoice.APEX_Amount_Paid__c = 1000;
InvoiceListToInsert.add(objNewInvoice);
Database.SaveResult[] srList = Database.insert(InvoiceListToInsert, false);

//Database method to insert the records in List
//Iterate through each returned result by the method

for (Database.SaveResult sr : srList) {
   if (sr.isSuccess()) {
     //This condition will be executed for successful records and will fetch the ids
     //of successful records
      System.debug('Successfully inserted Invoice. Invoice ID: ' + sr.getId());
     //Get the invoice id of inserted Account
   } else {
     //This condition will be executed for failed records
      for(Database.Error objErr : sr.getErrors()) {
         System.debug('The following error has occurred.');

        //Printing error message in Debug log
         System.debug(objErr.getStatusCode() + ': ' + objErr.getMessage());
         System.debug('Invoice oject field which are affected by the error:'
            + objErr.getFields());
      }
   }
}

更新操作

データベースメソッドを使用したビジネスケースの例を考えてみましょう。 Invoiceオブジェクトのステータスフィールドを更新する必要があると仮定しますが、同時に、レコードのステータス、失敗したレコードID、成功カウントなどの情報も必要です。 DMLステートメントを使用してこれを行うことはできないため、データベースメソッドを使用して操作のステータスを取得する必要があります。

請求書のステータスが「保留中」で、作成日が今日の場合、請求書の「ステータス」フィールドを更新します。

以下に示すコードは、Database.updateメソッドを使用して請求書レコードを更新するのに役立ちます。 また、このコードを実行する前に請求書レコードを作成します。

//Code to update the records using the Database methods
List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c,
   createdDate FROM APEX_Invoice__c WHERE createdDate = today];

//fetch the invoice created today
List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>();
for (APEX_Invoice__c objInvoice: invoiceList) {
   if (objInvoice.APEX_Status__c == 'Pending') {
      objInvoice.APEX_Status__c = 'Paid';
      updatedInvoiceList.add(objInvoice);   //Adding records to the list
   }
}

Database.SaveResult[] srList = Database.update(updatedInvoiceList, false);
//Database method to update the records in List

//Iterate through each returned result by the method
for (Database.SaveResult sr : srList) {
   if (sr.isSuccess()) {
     //This condition will be executed for successful records and will fetch
     //the ids of successful records
      System.debug('Successfully updated Invoice. Invoice ID is : ' + sr.getId());
   } else {
     //This condition will be executed for failed records
      for(Database.Error objErr : sr.getErrors()) {
         System.debug('The following error has occurred.');

        //Printing error message in Debug log
         System.debug(objErr.getStatusCode() + ': ' + objErr.getMessage());
         System.debug('Invoice oject field which are affected by the error:'
            + objErr.getFields());
      }
   }
}

このチュートリアルでは、挿入と更新の操作のみを見ていきます。 他の操作は、これらの操作と最後の章で行った操作に非常に似ています。

Apex-SOSL

すべてのビジネスまたはアプリケーションには、基本的な要件の1つとして検索機能があります。 このために、Salesforce.comはSOSLとSOQLを使用した2つの主要なアプローチを提供します。 この章では、SOSLアプローチについて詳しく説明します。

SOSL

オブジェクト全体およびフィールド全体でのテキスト文字列の検索は、SOSLを使用して行われます。 これはSalesforceオブジェクト検索言語です。 複数のオブジェクトにわたって特定の文字列を検索する機能があります。

SOSLステートメントは、sObjectのリストに評価されます。各リストには、特定のsObjectタイプの検索結果が含まれます。 結果リストは、SOSLクエリで指定された順序と同じ順序で常に返されます。

SOSLクエリの例

特定の文字列を検索できるプログラムを開発する必要があるビジネスケースを考えてみましょう。 InvoiceオブジェクトのCustomer Nameフィールドで文字列「ABC」を検索する必要があるとします。 コードは次のようになります-

まず、検索時に有効な結果を取得できるように、顧客名が「ABC」の請求書オブジェクトに単一のレコードを作成する必要があります。

//Program To Search the given string in all Object
//List to hold the returned results of sObject generic type
List<list<SObject>> invoiceSearchList = new List<List<SObject>>();

//SOSL query which will search for 'ABC' string in Customer Name field of Invoice Object
invoiceSearchList = [FIND 'ABC*' IN ALL FIELDS RETURNING APEX_Invoice_c
   (Id,APEX_Customer_r.Name)];

//Returned result will be printed
System.debug('Search Result '+invoiceSearchList);

//Now suppose, you would like to search string 'ABC' in two objects,
//that is Invoice and Account. Then for this query goes like this:

//Program To Search the given string in Invoice and Account object,
//you could specify more objects if you want, create an Account with Name as ABC.

//List to hold the returned results of sObject generic type
List<List<SObject>> invoiceAndSearchList = new List<List<SObject>>();

//SOSL query which will search for 'ABC' string in Invoice and in Account object's fields
invoiceAndSearchList = [FIND 'ABC*' IN ALL FIELDS RETURNING APEX_Invoice__c
   (Id,APEX_Customer__r.Name), Account];

//Returned result will be printed
System.debug('Search Result '+invoiceAndSearchList);

//This list will hold the returned results for Invoice Object
APEX_Invoice__c [] searchedInvoice = ((List<APEX_Invoice_c>)invoiceAndSearchList[0]);

//This list will hold the returned results for Account Object
Account [] searchedAccount = ((List<Account>)invoiceAndSearchList[1]);
System.debug('Value of searchedInvoice'+searchedInvoice+'Value of searchedAccount'
   + searchedAccount);

SOQL

これは、SOQLとほぼ同じです。 これを使用して、一度に1つのオブジェクトからのみオブジェクトレコードをフェッチできます。 ネストされたクエリを作成し、現在クエリしている親または子オブジェクトからレコードをフェッチすることもできます。

SOQLについては、次の章で説明します。

Apex-SOQL

これは、SFDCデータベースで動作するように設計されたSalesforceオブジェクトクエリ言語です。 単一のsObjectでのみ、指定された基準でレコードを検索できます。

SOSLと同様に、複数のオブジェクトを検索することはできませんが、ネストされたクエリをサポートします。

SOQLの例

化学会社の継続的な例を考えてみましょう。 今日作成され、顧客名が「test」ではないレコードのリストが必要だとします。 この場合、以下に示すようにSOQLクエリを使用する必要があります-

//fetching the Records via SOQL
List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();
InvoiceList = [SELECT Id, Name, APEX_Customer__r.Name, APEX_Status__c FROM
   APEX_Invoice__c WHERE createdDate = today AND APEX_Customer__r.Name != 'Test'];
//SOQL query for given criteria

//Printing the fetched records
System.debug('We have total '+InvoiceList.size()+' Records in List');

for (APEX_Invoice__c objInvoice: InvoiceList) {
   System.debug('Record Value is '+objInvoice);
  //Printing the Record fetched
}

以下に示すように、開発者コンソールのクエリエディターからSOQLクエリを実行できます。

開発者コンソールで以下のクエリを実行します。 今日作成された請求書レコードを検索します。

SELECT Id, Name, APEX_Customer__r.Name, APEX_Status__c FROM APEX_Invoice__c
   WHERE createdDate = today

値が必要なフィールドを選択する必要があります。そうしないと、ランタイムエラーがスローされる可能性があります。

関係フィールドの横断

これはSFDCで最も重要な部分の1つです。親子オブジェクトの関係を何度も走査する必要があるためです。

また、データベースに2つの関連オブジェクトレコードを挿入する必要がある場合があります。 たとえば、請求書オブジェクトは顧客オブジェクトと関係があるため、1人の顧客が多くの請求書を持つことができます。

請求書を作成していて、この請求書を顧客に関連付ける必要があるとします。 この機能には次のコードを使用できます-

//Now create the invoice record and relate it with the Customer object
//Before executing this, please create a Customer Records with Name 'Customer
//Creation Test'
APEX_Invoice__c objInvoice = new APEX_Invoice__c();

//Relating Invoice to customer via id field of Customer object
objInvoice.APEX_Customer__c = [SELECT id FROM APEX_Customer__c WHERE Name =
   'Customer Creation Test' LIMIT 1].id;
objInvoice.APEX_Status__c = 'Pending';
insert objInvoice; //Creating Invoice
System.debug('Newly Created Invoice'+objInvoice); //Newly created invoice

開発者コンソールでこのコードスニペットを実行します。 実行されたら、開発者コンソールから請求書のIDをコピーし、次に示すようにSFDCで同じものを開きます。 以下に示すように、親レコードがすでに請求書レコードに割り当てられていることがわかります。

親レコードのフェッチSOQL

子レコードの取得

ここで、特定の顧客レコードに関連するすべての請求書を1か所にまとめる必要がある例を考えてみましょう。 このためには、子関係の名前を知っている必要があります。 子関係名を表示するには、子オブジェクトのフィールド詳細ページに移動し、「子関係」値を確認します。 この例では、最後に__rが追加された請求書です。

この例では、データを設定し、「ABC Customer」レコードとして名前を持つ顧客を作成し、その顧客に3つの請求書を追加する必要があります。

ここで、顧客「ABC顧客」の請求書を取得します。 以下は、同じクエリです-

//Fetching Child Records using SOQL
List<apex_customer__c> ListCustomers = [SELECT Name, Id,
   (SELECT id, Name FROM Invoices__r) FROM APEX_Customer__c WHERE Name = 'ABC Customer'];

//Query for fetching the Child records along with Parent
System.debug('ListCustomers '+ListCustomers);//Parent Record

List<apex_invoice__c> ListOfInvoices = ListCustomers[0].Invoices__r;
//By this notation, you could fetch the child records and save it in List
System.debug('ListOfInvoices values of Child '+ListOfInvoices);
//Child records

デバッグログでレコード値を確認できます。

親レコードの取得

作成日が今日である請求書の顧客名を取得する必要があると仮定します。それから、以下のクエリを使用して同じことができます-

子オブジェクトとともに親レコードの値を取得します。

//Fetching Parent Record Field value using SOQL
List<apex_invoice__c> ListOfInvoicesWithCustomerName = new List<apex_invoice__c>();
ListOfInvoicesWithCustomerName = [SELECT Name, id, APEX_Customer__r.Name
   FROM APEX_Invoice__c LIMIT 10];

//Fetching the Parent record's values
for (APEX_Invoice__c objInv: ListOfInvoicesWithCustomerName) {
   System.debug('Invoice Customer Name is '+objInv.APEX_Customer__r.Name);
  //Will print the values, all the Customer Records will be printed
}

ここでは、表記APEX_Customerr.Nameを使用しました。APEX_Customerrは親関係名です。ここでは、Parentフィールドの最後に__rを追加する必要があり、その後、親フィールドの値を取得できます。

集約関数

SOQLには、SQLにあるような集約関数があります。 集計関数を使用すると、データをロールアップして集計できます。 関数を詳細に理解しましょう。

顧客「ABC顧客」から得ている平均収益が何であるかを知りたい場合、この関数を使用して平均を取得できます。

//Getting Average of all the invoices for a Perticular Customer
AggregateResult[] groupedResults = [SELECT
   AVG(APEX_Amount_Paid__c)averageAmount FROM APEX_Invoice__c WHERE
   APEX_Customer__r.Name = 'ABC Customer'];
Object avgPaidAmount = groupedResults[0].get('averageAmount');
System.debug('Total Average Amount Received From Customer ABC is '+avgPaidAmount);

デバッグログの出力を確認します。 集計関数を含むクエリは、結果を AggregateResult オブジェクトの配列で返すことに注意してください。 AggregateResultは読み取り専用のsObjectであり、クエリ結果にのみ使用されます。 大きなデータに関するレポートを生成する必要がある場合に役立ちます。

データ集計を実行するために使用できる他の集計関数もあります。

  • MIN()*-これは最小値を見つけるために使用できます
  • MAX()*-これは最大値を見つけるために使用できます。

Apex変数のバインド

SOQLクエリでApex変数を使用して、目的の結果を取得できます。 Apex変数は、コロン(:)表記で参照できます。

//Apex Variable Reference
String CustomerName = 'ABC Customer';
List<apex_customer__c> ListCustomer = [SELECT Id, Name FROM APEX_Customer__c
   WHERE Name = :CustomerName];

//Query Using Apex variable
System.debug('ListCustomer Name'+ListCustomer);//Customer Name

Apex-セキュリティ

Apexセキュリティとは、セキュリティ設定を適用し、コードの実行時に共有ルールを適用するプロセスを指します。 Apexクラスには、2つのキーワードで制御できるセキュリティ設定があります。

データセキュリティと共有ルール

Apexは通常、システムコンテキスト、つまり現在のユーザーの権限で実行されます。 フィールドレベルのセキュリティ、および共有ルールは、コード実行中に考慮されません。 コードを実行しているユーザーの許可を得て、匿名ブロックコードのみが実行されます。

Apexコードは、セキュリティおよび共有設定によって隠されている機密データをユーザーに公開しないでください。 したがって、Apexセキュリティと共有ルールの適用が最も重要です。

共有キーワードあり

このキーワードを使用すると、Apexコードは現在のユーザーの共有設定をApexコードに適用します。 これは、プロファイル権限を強制するのではなく、データレベルの共有設定のみを強制します。

ユーザーが5つのレコードにアクセスできるが、レコードの総数は10である例を考えてみましょう。 そのため、Apexクラスが「With Sharing」キーワードで宣言されると、ユーザーがアクセスできる5つのレコードのみが返されます。

まず、Customerオブジェクトに少なくとも5つのレコードの「Name」を「ABC Customer」として、残りの5つのレコードを「XYZ Customer」として少なくとも10個のレコードを作成したことを確認します。 次に、「ABCカスタマー」をすべてのユーザーと共有する共有ルールを作成します。 また、CustomerオブジェクトのOWDをプライベートとして設定したことを確認する必要があります。

下記のコードを開発者コンソールの匿名ブロックに貼り付けます。

//Class With Sharing
public with sharing class MyClassWithSharing {
  //Query To fetch 10 records
   List<apex_customer__c> CustomerList = [SELECT id, Name FROM APEX_Customer__c LIMIT 10];

   public Integer executeQuery () {
      System.debug('List will have only 5 records and the actual records are'
         + CustomerList.size()+' as user has access to'+CustomerList);
      Integer ListSize = CustomerList.size();
      return ListSize;
   }
}

//Save the above class and then execute as below
//Execute class using the object of class
MyClassWithSharing obj = new MyClassWithSharing();
Integer ListSize = obj.executeQuery();

キーワードを共有しない

名前が示すように、このキーワードで宣言されたクラスはシステムモードで実行されます。つまり、ユーザーのレコードへのアクセスに関係なく、クエリはすべてのレコードをフェッチします。

//Class Without Sharing
public without sharing class MyClassWithoutSharing {
   List<apex_customer__c> CustomerList = [SELECT id, Name FROM APEX_Customer__c LIMIT 10];

  //Query To fetch 10 records, this will return all the records
   public Integer executeQuery () {
      System.debug('List will have only 5 records and the actula records are'
         + CustomerList.size()+' as user has access to'+CustomerList);
      Integer ListSize = CustomerList.size();
      return ListSize;
   }
}
//Output will be 10 records.

Apexクラスのセキュリティの設定

特定のプロファイルのApexクラスを有効または無効にすることができます。 同じ手順を以下に示します。 どのプロファイルがどのクラスにアクセスする必要があるかを決定できます。

クラスリストページからApexクラスセキュリティを設定する

  • ステップ1 *-[設定]から、[開発]→[Apexクラス]をクリックします。

Apex Cass Security Step1の設定

  • ステップ2 *-制限するクラスの名前をクリックします。 CustomerOperationClassをクリックしました。

Apex Cass Security Step2の設定

  • ステップ3 *-[セキュリティ]をクリックします。

Apex Cass Security Step3の設定

  • ステップ4 *-有効にするプロファイルを[利用可能なプロファイル]リストから選択して[追加]をクリックするか、無効にするプロファイルを[有効なプロファイル]リストから選択して[削除]をクリックします。

Apexクラスセキュリティの設定Step3

  • ステップ5 *-[保存]をクリックします。

権限セットからApexセキュリティを設定する

  • ステップ1 *-[設定]から、[ユーザーの管理]→[権限セット]をクリックします。

PermissionsetセットからのApexクラスセキュリティの設定Step1

  • ステップ2 *-権限セットを選択します。

PermissionsetからApexクラスのセキュリティを設定ステップ2

  • ステップ3 *-[Apexクラスアクセス]をクリックします。

PermissionsetからApexクラスのセキュリティを設定ステップ3

  • ステップ4 *-[編集]をクリックします。

権限セットのステップ4からApexクラスのセキュリティを設定

  • ステップ5 *-有効にするApexクラスを[利用可能なApexクラス]リストから選択して[追加]をクリックするか、無効にするApexクラスを[有効なApexクラス]リストから選択して[削除]をクリックします。

PermissionsetからApexクラスのセキュリティを設定ステップ5

  • ステップ6 *-[保存]ボタンをクリックします。

Apex-呼び出し

Apex呼び出しは、Apexクラスを実行するプロセスを指します。 Apexクラスは、以下にリストされている方法のいずれかを介して呼び出された場合にのみ実行できます-

  • トリガーと匿名ブロック
  • 指定されたイベントに対して呼び出されるトリガー
  • 非同期Apex
  • 指定した間隔で実行するApexクラスのスケジュール、またはバッチジョブの実行
  • Webサービスクラス
  • Apex Email Serviceクラス
  • SOAPおよびREST Webサービスを介してメソッドを公開できるApex Webサービス
  • Visualforceコントローラー
  • 受信メールを処理するApexメールサービス
  • JavaScriptを使用してApexを呼び出す
  • Apexに実装されたWebサービスメソッドを呼び出すAjaxツールキット

Apexを呼び出す一般的な方法をいくつか理解します。

匿名ブロックの実行から

以下に示すように、開発者コンソールで匿名を実行してApexクラスを呼び出すことができます-

  • ステップ1 *-開発者コンソールを開きます。
  • ステップ2 *-[デバッグ]をクリックします。

Apex Invoking From Execute Anonymous Step1

  • ステップ3 *-以下に示すように、匿名ウィンドウの実行が開きます。 今、実行ボタンをクリックしてください-

Apex Invoking From Execute Anonymous Step2

  • ステップ4 *-[ログ]ペインに表示されるデバッグログを開きます。

匿名実行ステップ3からのApex呼び出し

トリガーから

トリガーからApexクラスを呼び出すこともできます。 指定されたイベントが発生するとトリガーが呼び出され、実行時にトリガーがApexクラスを呼び出すことができます。

以下は、トリガーが呼び出されたときにクラスが実行される方法を示すサンプルコードです。

//Class which will gets called from trigger
public without sharing class MyClassWithSharingTrigger {

   public static Integer executeQuery (List<apex_customer__c> CustomerList) {
     //perform some logic and operations here
      Integer ListSize = CustomerList.size();
      return ListSize;
   }
}

//Trigger Code
trigger Customer_After_Insert_Example on APEX_Customer__c (after insert) {
   System.debug('Trigger is Called and it will call Apex Class');
   MyClassWithSharingTrigger.executeQuery(Trigger.new); //Calling Apex class and
                                                        //method of an Apex class
}

//This example is for reference, no need to execute and will have detail look on
//triggers later chapters.

Visualforceページコントローラーコードから

Apexクラスは、Visualforceページからも呼び出すことができます。 コントローラまたはコントローラ拡張を指定すると、指定されたApexクラスが呼び出されます。

  • VFページコード*

VFページStep1からのApex呼び出し

  • Apexクラスコード(コントローラー拡張)*

VFページStep2からのApex呼び出し

Apex-トリガー

Apexトリガーは、特定のイベントが発生したときに実行されるストアドプロシージャのようなものです。 トリガーは、イベントが記録上で発生する前後に実行されます。

構文

trigger triggerName on ObjectName (trigger_events) { Trigger_code_block }

トリガーの実行

以下は、トリガーをモミできるイベントです-

  • インサート
  • 更新
  • 削除する
  • マージ
  • アップサート
  • 元に戻す

トリガーの例1

顧客の[顧客ステータス]フィールドが非アクティブからアクティブに変更されたときに請求書レコードを作成する必要があるというビジネス要件を受け取ったとします。 このため、次の手順に従ってAPEX_Customer__cオブジェクトにトリガーを作成します-

  • ステップ1 *-sObjectに移動
  • ステップ2 *-顧客をクリックします
  • ステップ3 *-トリガー関連リストの「新規」ボタンをクリックし、以下のようにトリガーコードを追加します。
//Trigger Code
trigger Customer_After_Insert on APEX_Customer__c (after update) {
   List InvoiceList = new List();

   for (APEX_Customer__c objCustomer: Trigger.new) {

      if (objCustomer.APEX_Customer_Status__c == 'Active') {
         APEX_Invoice__c objInvoice = new APEX_Invoice__c();
         objInvoice.APEX_Status__c = 'Pending';
         InvoiceList.add(objInvoice);
      }
   }

  //DML to insert the Invoice List in SFDC
   insert InvoiceList;
}

説明

*Trigger.new* -これは、現在挿入または更新されているトリガーコンテキストにあるレコードを格納するコンテキスト変数です。 この場合、この変数には、更新されたCustomerオブジェクトのレコードがあります。

コンテキストで利用できる他のコンテキスト変数があります-trigger.old、trigger.newMap、trigger.OldMap。

トリガーの例2

上記のトリガーは、顧客レコードに更新操作があるときに実行されます。 毎回ではなく、顧客ステータスが非アクティブからアクティブに変更された場合にのみ、請求書レコードを挿入する必要があるとします。このために、キーをレコードIDとして、値を古いレコード値として保存する別のコンテキスト変数 trigger.oldMap を使用できます。

//Modified Trigger Code
trigger Customer_After_Insert on APEX_Customer__c (after update) {
   List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();

   for (APEX_Customer__c objCustomer: Trigger.new) {

     //condition to check the old value and new value
      if (objCustomer.APEX_Customer_Status__c == 'Active' &&

      trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
         APEX_Invoice__c objInvoice = new APEX_Invoice__c();
         objInvoice.APEX_Status__c = 'Pending';
         InvoiceList.add(objInvoice);
      }
   }

  //DML to insert the Invoice List in SFDC
   insert InvoiceList;
}

説明

前述のTrigger.oldMap変数を使用しました。これは、更新中のレコードのIDと古い値を格納するコンテキスト変数です。

Apex-トリガーデザインパターン

設計パターンは、コードをより効率的にし、ガバナーの制限に達しないようにするために使用されます。 多くの場合、開発者はオブジェクトのインスタンス化を繰り返す非効率的なコードを作成できます。 これにより、非効率でパフォーマンスの低いコードが発生し、ガバナーの制限に違反する可能性があります。 これは、トリガーで最も一般的に発生します。トリガーは一連のレコードに対して操作できるためです。

この章では、いくつかの重要な設計パターン戦略について説明します。

バルクトリガーのデザインパターン

実際のビジネスケースでは、一度に数千のレコードを処理する必要がある場合があります。 トリガーがそのような状況を処理するように設計されていない場合、レコードの処理中に失敗する可能性があります。 トリガーを実装する際に従うべきベストプラクティスがいくつかあります。 デフォルトでは、すべてのトリガーは一括トリガーであり、一度に複数のレコードを処理できます。 一度に複数のレコードを処理することを常に計画する必要があります。

多数のレコードを処理する必要があり、以下に示すようにトリガーを記述したビジネスケースを考えます。 これは、顧客ステータスが非アクティブからアクティブに変更されたときに請求書レコードを挿入するために取った同じ例です。

//Bad Trigger Example
trigger Customer_After_Insert on APEX_Customer__c (after update) {

   for (APEX_Customer__c objCustomer: Trigger.new) {

      if (objCustomer.APEX_Customer_Status__c == 'Active' &&
         trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {

        //condition to check the old value and new value
         APEX_Invoice__c objInvoice = new APEX_Invoice__c();
         objInvoice.APEX_Status__c = 'Pending';
         insert objInvoice;  //DML to insert the Invoice List in SFDC
      }
   }
}

ループブロック用にDMLステートメントが書き込まれていることがわかります。これは、少数のレコードのみを処理する場合に機能しますが、数百のレコードを処理する場合は、トランザクションごとのDMLステートメントの制限である governor limit 。 ガバナー制限の詳細については、後続の章で説明します。

これを回避するには、一度に複数のレコードを処理するためにトリガーを効率的にする必要があります。

次の例は、同じことを理解するのに役立ちます-

//Modified Trigger Code-Bulk Trigger
trigger Customer_After_Insert on APEX_Customer__c (after update) {
   List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();

   for (APEX_Customer__c objCustomer: Trigger.new) {

      if (objCustomer.APEX_Customer_Status__c == 'Active' &&
         trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {

        //condition to check the old value and new value
         APEX_Invoice__c objInvoice = new APEX_Invoice__c();
         objInvoice.APEX_Status__c = 'Pending';
         InvoiceList.add(objInvoice);//Adding records to List
      }
   }

   insert InvoiceList;
  //DML to insert the Invoice List in SFDC, this list contains the all records
  //which need to be modified and will fire only one DML
}

このトリガーはリストを操作し、リストには変更が必要なすべてのレコードがあるため、1つのDMLステートメントのみを起動します。

この方法により、DMLステートメントガバナーの制限を回避できます。

トリガーヘルパークラス

トリガーでコード全体を書くことも良い習慣ではありません。 したがって、以下に示すように、Apexクラスを呼び出して、トリガーからApexクラスに処理を委任する必要があります。 トリガーヘルパークラスは、トリガーのすべての処理を行うクラスです。

請求書レコードの作成例をもう一度考えてみましょう。

//Below is the Trigger without Helper class
trigger Customer_After_Insert on APEX_Customer__c (after update) {
   List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();

   for (APEX_Customer__c objCustomer: Trigger.new) {

      if (objCustomer.APEX_Customer_Status__c == 'Active' &&
         trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {

        //condition to check the old value and new value
         APEX_Invoice__c objInvoice = new APEX_Invoice__c();
         objInvoice.APEX_Status__c = 'Pending';
         InvoiceList.add(objInvoice);
      }
   }

   insert InvoiceList;//DML to insert the Invoice List in SFDC
}

//Below is the trigger with helper class
//Trigger with Helper Class
trigger Customer_After_Insert on APEX_Customer__c (after update) {
   CustomerTriggerHelper.createInvoiceRecords(Trigger.new, trigger.oldMap);
  //Trigger calls the helper class and does not have any code in Trigger
}

ヘルパークラス

public class CustomerTriggerHelper {
   public static void createInvoiceRecords (List<apex_customer__c>

   customerList, Map<id, apex_customer__c> oldMapCustomer) {
      List<apex_invoice__c> InvoiceList = new Listvapex_invoice__c>();

      for (APEX_Customer__c objCustomer: customerList) {

         if (objCustomer.APEX_Customer_Status__c == 'Active' &&
            oldMapCustomer.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {

           //condition to check the old value and new value
            APEX_Invoice__c objInvoice = new APEX_Invoice__c();

           //objInvoice.APEX_Status__c = 'Pending';
            InvoiceList.add(objInvoice);
         }
      }

      insert InvoiceList; //DML to insert the Invoice List in SFDC
   }
}

これでは、すべての処理がヘルパークラスに委任され、新しい機能が必要な場合は、トリガーを変更せずに単純にコードをヘルパークラスに追加できます。

各sObjectでの単一のトリガー

オブジェクトごとに常に単一のトリガーを作成します。 同じオブジェクトで複数のトリガーが発生すると、ガバナーの制限に達すると競合とエラーが発生する可能性があります。

コンテキスト変数を使用して、要件に応じてヘルパークラスからさまざまなメソッドを呼び出すことができます。 前の例を考えてみましょう。 createInvoiceメソッドは、レコードが更新され、複数のイベントが発生したときにのみ呼び出されると仮定します。 その後、次のように実行を制御できます-

//Trigger with Context variable for controlling the calling flow
trigger Customer_After_Insert on APEX_Customer__c (after update, after insert) {

   if (trigger.isAfter && trigger.isUpdate) {
     //This condition will check for trigger events using isAfter and isUpdate
     //context variable
      CustomerTriggerHelper.createInvoiceRecords(Trigger.new);

     //Trigger calls the helper class and does not have any code in Trigger
     //and this will be called only when trigger ids after update
   }
}

//Helper Class
public class CustomerTriggerHelper {

  //Method To Create Invoice Records
   public static void createInvoiceRecords (List<apex_customer__c> customerList) {

      for (APEX_Customer__c objCustomer: customerList) {

         if (objCustomer.APEX_Customer_Status__c == 'Active' &&
            trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {

           //condition to check the old value and new value
            APEX_Invoice__c objInvoice = new APEX_Invoice__c();
            objInvoice.APEX_Status__c = 'Pending';
            InvoiceList.add(objInvoice);
         }
      }

      insert InvoiceList;//DML to insert the Invoice List in SFDC
   }
}

Apex-ガバナーの制限

ガバナーの実行制限により、Force.comマルチテナントプラットフォーム上のリソースを効率的に使用できます。 これは、効率的な処理のためのコード実行に関してSalesforce.comによって指定された制限です。

ガバナー制限とは何ですか?

知っているように、Apexはマルチテナント環境で実行されます。つまり、単一のリソースがすべての顧客と組織で共有されます。 したがって、誰もリソースを独占しないようにする必要があります。したがって、Salesforce.comは、コード実行を管理および制限する一連の制限を作成しました。 ガバナーの制限のいずれかを超えると、エラーがスローされ、プログラムの実行が停止します。

開発者の観点からは、コードがスケーラブルであり、制限に達していないことを確認することが重要です。

これらの制限はすべて、トランザクションごとに適用されます。 単一のトリガーの実行は1つのトランザクションです。

これまで見てきたように、トリガー設計パターンは制限エラーを回避するのに役立ちます。 他の重要な制限が表示されます。

SOQLクエリ制限の回避

トランザクションごとに発行できるクエリは100のみです。つまり、コードが100を超えるSOQLクエリを発行すると、エラーがスローされます。

この例は、SOQLクエリの制限に到達する方法を示しています-

次のトリガーは、顧客のリストを反復処理し、子レコード(請求書)の説明を文字列「Ok to Pay」で更新します。

//Helper class:Below code needs o be checked.
public class CustomerTriggerHelper {

  public static void isAfterUpdateCall(Trigger.new) {
      createInvoiceRecords(trigger.new);//Method call
      updateCustomerDescription(trigger.new);
   }

  //Method To Create Invoice Records
   public static void createInvoiceRecords (List<apex_customer__c> customerList) {
      for (APEX_Customer__c objCustomer: customerList) {

         if (objCustomer.APEX_Customer_Status__c == 'Active' &&
            trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {

           //condition to check the old value and new value
            APEX_Invoice__c objInvoice = new APEX_Invoice__c();
            objInvoice.APEX_Status__c = 'Pending';
            InvoiceList.add(objInvoice);
         }
      }
      insert InvoiceList;//DML to insert the Invoice List in SFDC
   }

  //Method to update the invoice records
   public static updateCustomerDescription (List<apex_customer__c> customerList) {
      for (APEX_Customer__c objCust: customerList) {
         List<apex_customer__c> invList = [SELECT Id, Name,
            APEX_Description__c FROM APEX_Invoice__c WHERE APEX_Customer__c = :objCust.id];

        //This query will fire for the number of records customer list has and will
        //hit the governor limit when records are more than 100
         for (APEX_Invoice__c objInv: invList) {
            objInv.APEX_Description__c = 'OK To Pay';
            update objInv;
           //Update invoice, this will also hit the governor limit for DML if large
           //number(150) of records are there
         }
      }
   }
}

「updateCustomerDescription」メソッドが呼び出され、顧客レコードの数が100を超えると、SOQL制限に達します。 これを回避するには、ForループでSOQLクエリを記述しないでください。 この場合、SOQLクエリはForループで記述されています。

以下は、DMLおよびSOQLの制限を回避する方法を示す例です。 ネストされた関係クエリを使用して請求書レコードを取得し、コンテキスト変数 trigger.newMap を使用してidおよびCustomerレコードのマップを取得しました。

//SOQL-Good Way to Write Query and avoid limit exception
//Helper Class
public class CustomerTriggerHelper {
   public static void isAfterUpdateCall(Trigger.new) {
      createInvoiceRecords(trigger.new); //Method call
      updateCustomerDescription(trigger.new, trigger.newMap);
   }

  //Method To Create Invoice Records
   public static void createInvoiceRecords (List<apex_customer__c> customerList) {
      for (APEX_Customer__c objCustomer: customerList) {

         if (objCustomer.APEX_Customer_Status__c == 'Active' &&
            trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {

           //condition to check the old value and new value
            APEX_Invoice__c objInvoice = new APEX_Invoice__c();
            objInvoice.APEX_Status__c = 'Pending';
            InvoiceList.add(objInvoice);
         }
      }
      insert InvoiceList;//DML to insert the Invoice List in SFDC
   }

  //Method to update the invoice records
   public static updateCustomerDescription (List<apex_customer__c>
      customerList, Map<id, apex_customer__c> newMapVariable) {
      List<apex_customer__c> customerListWithInvoice = [SELECT id,
         Name,(SELECT Id, Name, APEX_Description__c FROM APEX_Invoice__r) FROM
         APEX_Customer__c WHERE Id IN :newMapVariable.keySet()];

     //Query will be for only one time and fetches all the records
      List<apex_invoice__c> invoiceToUpdate = new
      List<apex_invoice__c>();

      for (APEX_Customer__c objCust: customerList) {
         for (APEX_Invoice__c objInv: invList) {
            objInv.APEX_Description__c = 'OK To Pay';
            invoiceToUpdate.add(objInv);
           //Add the modified records to List
         }
      }
      update invoiceToUpdate;
   }
}

DML一括呼び出し

この例は、バルクトリガーとトリガーヘルパークラスパターンを示しています。 最初にヘルパークラスを保存してから、トリガーを保存する必要があります。

-以前に作成した「CustomerTriggerHelper」クラスに以下のコードを貼り付けます。

//Helper Class
public class CustomerTriggerHelper {
   public static void isAfterUpdateCall(List<apex_customer__c> customerList,
      Map<id, apex_customer__c> mapIdToCustomers, Map<id, apex_customer__c>
      mapOldItToCustomers) {
      createInvoiceRecords(customerList, mapOldItToCustomers);  //Method call
      updateCustomerDescription(customerList,mapIdToCustomers,
      mapOldItToCustomers);
   }

  //Method To Create Invoice Records
   public static void createInvoiceRecords (List<apex_customer__c>
      customerList, Map<id, apex_customer__c> mapOldItToCustomers) {
      List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();
      List<apex_customer__c> customerToInvoice = [SELECT id, Name FROM
         APEX_Customer__c LIMIT 1];

      for (APEX_Customer__c objCustomer: customerList) {
         if (objCustomer.APEX_Customer_Status__c == 'Active' &&
            mapOldItToCustomers.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
           //condition to check the old value and new value
            APEX_Invoice__c objInvoice = new APEX_Invoice__c();
            objInvoice.APEX_Status__c = 'Pending';
            objInvoice.APEX_Customer__c = objCustomer.id;
            InvoiceList.add(objInvoice);
         }
      }
      system.debug('InvoiceList&&&'+InvoiceList);
      insert InvoiceList;
     //DML to insert the Invoice List in SFDC. This also follows the Bulk pattern
   }

  //Method to update the invoice records
   public static void updateCustomerDescription (List<apex_customer__c>
      customerList, Map<id, apex_customer__c> newMapVariable, Map<id,
      apex_customer__c> oldCustomerMap) {
      List<apex_customer__c> customerListWithInvoice = [SELECT id,
      Name,(SELECT Id, Name, APEX_Description__c FROM Invoices__r) FROM
         APEX_Customer__c WHERE Id IN :newMapVariable.keySet()];

     //Query will be for only one time and fetches all the records
      List<apex_invoice__c> invoiceToUpdate = new List<apex_invoice__c>();
      List<apex_invoice__c> invoiceFetched = new List<apex_invoice__c>();
      invoiceFetched = customerListWithInvoice[0].Invoices__r;
      system.debug('invoiceFetched'+invoiceFetched);
      system.debug('customerListWithInvoice****'+customerListWithInvoice);

      for (APEX_Customer__c objCust: customerList) {
         system.debug('objCust.Invoices__r'+objCust.Invoices__r);
         if (objCust.APEX_Active__c == true &&
            oldCustomerMap.get(objCust.id).APEX_Active__c == false) {
            for (APEX_Invoice__c objInv: invoiceFetched) {
               system.debug('I am in For Loop'+objInv);
               objInv.APEX_Description__c = 'OK To Pay';
               invoiceToUpdate.add(objInv);
              //Add the modified records to List
            }
         }
      }
     system.debug('Value of List ***'+invoiceToUpdate);
     update invoiceToUpdate;
     //This statement is Bulk DML which performs the DML on List and avoids
     //the DML Governor limit
   }
}

//Trigger Code for this class: Paste this code in 'Customer_After_Insert'
//trigger on Customer Object
trigger Customer_After_Insert on APEX_Customer__c (after update) {
   CustomerTriggerHelper.isAfterUpdateCall(Trigger.new, trigger.newMap,
      trigger.oldMap);
  //Trigger calls the helper class and does not have any code in Trigger
}

Salesforceガバナーのその他の制限

次の表に、重要なガバナーの制限を示します。

Description Limit
Total heap size 6 MB/12 MB
Total number of DML statements issued 150
Total number of records retrieved by a single SOSL query 2000
Total number of SOSL queries issued 20
Total number of records retrieved by Database.getQueryLocator 10000
Total number of records retrieved by SOQL queries 50000

Apex-バッチ処理

この章では、Apexでのバッチ処理について説明します。 おそらく、データのクリーニングや未使用データの削除など、多数のレコードを毎日処理するシナリオを考えてみてください。

Apexの一括処理とは何ですか?

Apexの一括処理はApexコードの非同期実行であり、多数のレコードを処理するために特別に設計されており、同期コードよりもガバナ制限の柔軟性が高くなっています。

Apexの一括処理を使用する場合

  • 毎日または特定の時間間隔で大量のレコードを処理する場合は、Apexの一括処理を使用できます。
  • また、操作を非同期にする場合は、Apexの一括処理を実装できます。 Apexの一括処理は、開発者が実装する必要があるインターフェースとして公開されます。 Apexを使用して、バッチジョブを実行時にプログラムで呼び出すことができます。 バッチApexは、レコードセット全体をカバーし、処理を管理可能なデータチャンクに分割して、レコードの小さなバッチで動作します。

Apexの一括使用

Apexの一括処理を使用する場合、Salesforceが提供するインターフェイスDatabase.Batchableを実装してから、プログラムでクラスを呼び出す必要があります。

次の手順に従うことで、クラスを監視できます-

Apex一括処理ジョブの実行を監視または停止するには、[設定]→[監視]→[Apexジョブ]または[ジョブ]→[Apexジョブ]に移動します。

Apexバッチステップ1の監視

Apex Batch Step2の監視

Database.Batchableインターフェイスには、実装する必要がある次の3つのメソッドがあります-

  • 開始
  • 実行する
  • 終了

ここで、各メソッドを詳細に理解しましょう。

開始

Startメソッドは、Database.Batchableインターフェイスの3つのメソッドの1つです。

構文

global void execute(Database.BatchableContext BC, list<sobject<) {}

このメソッドは、バッチジョブの開始時に呼び出され、バッチジョブが動作するデータを収集します。

メソッドを理解するために、次の点を考慮してください-

  • 単純なクエリを使用してバッチジョブで使用されるオブジェクトのスコープを生成する場合は、 Database.QueryLocator オブジェクトを使用します。 この場合、SOQLデータ行の制限はバイパスされます。
  • レコードを処理する複雑な基準がある場合は、反復可能オブジェクトを使用します。 Database.QueryLocatorは、処理するレコードの範囲を決定します。

実行する

Database.BatchableインターフェースのExecuteメソッドを理解しましょう。

構文

global void execute(Database.BatchableContext BC, list<sobject<) {}

ここで、list <sObject <はDatabase.QueryLocatorメソッドによって返されます。

このメソッドは、Startメソッドの後に呼び出され、バッチジョブに必要なすべての処理を実行します。

終了

Database.BatchableインターフェースのFinishメソッドについて説明します。

  • 構文 *
global void finish(Database.BatchableContext BC) {}

このメソッドは最後に呼び出され、処理されたバッチジョブレコードとステータスに関する情報を電子メールで送信するなど、いくつかの仕上げアクティビティを実行できます。

Apexの一括処理の例

既存の化学会社の例を考えて、アクティブとしてマークされ、今日として日付を作成した顧客レコードの顧客ステータスおよび顧客説明フィールドを更新する必要があると仮定します。 これは毎日行う必要があり、バッチ処理のステータスに関するメールをユーザーに送信する必要があります。 顧客のステータスを「処理済み」に、顧客の説明を「バッチジョブ経由で更新」に更新します。

//Batch Job for Processing the Records
global class CustomerProessingBatch implements Database.Batchable<sobject> {
   global String [] email = new String[] {'[email protected]'};
  //Add here your email address here

  //Start Method
   global Database.Querylocator start (Database.BatchableContext BC) {
      return Database.getQueryLocator('Select id, Name, APEX_Customer_Status__c,
      APEX_Customer_Decscription__c From APEX_Customer__c WHERE createdDate = today
      AND APEX_Active__c = true');
     //Query which will be determine the scope of Records fetching the same
   }

  //Execute method
   global void execute (Database.BatchableContext BC, List<sobject> scope) {
      List<apex_customer__c> customerList = new List<apex_customer__c>();
      List<apex_customer__c> updtaedCustomerList = new List<apex_customer__c>();

     //List to hold updated customer
      for (sObject objScope: scope) {
         APEX_Customer__c newObjScope = (APEX_Customer__c)objScope ;

        //type casting from generic sOject to APEX_Customer__c
         newObjScope.APEX_Customer_Decscription__c = 'Updated Via Batch Job';
         newObjScope.APEX_Customer_Status__c = 'Processed';
         updtaedCustomerList.add(newObjScope);//Add records to the List
         System.debug('Value of UpdatedCustomerList '+updtaedCustomerList);
      }

      if (updtaedCustomerList != null && updtaedCustomerList.size()>0) {
        //Check if List is empty or not
         Database.update(updtaedCustomerList); System.debug('List Size '
          + updtaedCustomerList.size());
        //Update the Records
      }
   }

  //Finish Method
   global void finish(Database.BatchableContext BC) {
      Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();

     //Below code will fetch the job Id
      AsyncApexJob a = [Select a.TotalJobItems, a.Status, a.NumberOfErrors,
      a.JobType, a.JobItemsProcessed, a.ExtendedStatus, a.CreatedById,
      a.CompletedDate From AsyncApexJob a WHERE id = :BC.getJobId()];

     //get the job Id
      System.debug('$$$ Jobid is'+BC.getJobId());

     //below code will send an email to User about the status
      mail.setToAddresses(email);
      mail.setReplyTo('[email protected]');//Add here your email address
      mail.setSenderDisplayName('Apex Batch Processing Module');
      mail.setSubject('Batch Processing '+a.Status);
      mail.setPlainTextBody('The Batch Apex job processed'
         + a.TotalJobItems+'batches with '+a.NumberOfErrors+'failures'+'Job Item
      processed are'+a.JobItemsProcessed);
      Messaging.sendEmail(new Messaging.Singleemailmessage [] {mail});
   }
}

このコードを実行するには、まず保存してから、次のコードを匿名実行に貼り付けます。 これにより、クラスのオブジェクトが作成され、Database.executeメソッドがバッチジョブを実行します。 ジョブが完了すると、指定したメールアドレスにメールが送信されます。* アクティブ*がオンになっている顧客レコードがあることを確認してください。

//Paste in Developer Console
CustomerProessingBatch objClass = new CustomerProessingBatch();
Database.executeBatch (objClass);

このクラスが実行されたら、情報が記載されたメールを受信する場所に指定したメールアドレスを確認します。 また、上記の監視ページと手順を使用して、バッチジョブのステータスを確認できます。

デバッグログを確認すると、処理されたレコードの数を示すリストサイズを見つけることができます。

制限事項

一度に処理できるバッチジョブは5つだけです。 これは、Apexの一括処理の制限の1つです。

Apex詳細ページを使用したApexバッチジョブのスケジュール

以下に示すように、Apex詳細ページからApexクラスをスケジュールできます-

  • ステップ1 *-[設定]⇒[Apexクラス]に移動し、[Apexクラス]をクリックします。

詳細ページStep1からApexをスケジュールする

  • ステップ2 *-[Apexのスケジュール]ボタンをクリックします。

詳細ページStep2からApexをスケジュール

  • ステップ3 *-詳細を提供します。

詳細ページStep3からApexをスケジュールする

スケジュール可能なインターフェイスを使用したApexバッチジョブのスケジュール

以下に示すように、スケジュール可能なインターフェイスを使用してApexバッチジョブをスケジュールできます-

//Batch Job for Processing the Records
global class CustomerProessingBatch implements Database.Batchable<sobject> {
   global String [] email = new String[] {'[email protected]'};
  //Add here your email address here

  //Start Method
   global Database.Querylocator start (Database.BatchableContext BC) {
      return Database.getQueryLocator('Select id, Name, APEX_Customer_Status__c,
      APEX_Customer_Decscription__c From APEX_Customer__c WHERE createdDate = today
      AND APEX_Active__c = true');
     //Query which will be determine the scope of Records fetching the same
   }

  //Execute method
   global void execute (Database.BatchableContext BC, List<sobject> scope) {
      List<apex_customer__c> customerList = new List<apex_customer__c>();
      List<apex_customer__c> updtaedCustomerList = new
      List<apex_customer__c>();//List to hold updated customer

      for (sObject objScope: scope) {
         APEX_Customer__c newObjScope = (APEX_Customer__c)objScope ;//type
         casting from generic sOject to APEX_Customer__c
         newObjScope.APEX_Customer_Decscription__c = 'Updated Via Batch Job';
         newObjScope.APEX_Customer_Status__c = 'Processed';
         updtaedCustomerList.add(newObjScope);//Add records to the List
         System.debug('Value of UpdatedCustomerList '+updtaedCustomerList);
      }

      if (updtaedCustomerList != null && updtaedCustomerList.size()>0) {
        //Check if List is empty or not
         Database.update(updtaedCustomerList); System.debug('List Size'
            + updtaedCustomerList.size());
        //Update the Records
      }
   }

  //Finish Method
   global void finish(Database.BatchableContext BC) {
      Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();

     //Below code will fetch the job Id
      AsyncApexJob a = [Select a.TotalJobItems, a.Status, a.NumberOfErrors,
      a.JobType, a.JobItemsProcessed, a.ExtendedStatus, a.CreatedById,
      a.CompletedDate From AsyncApexJob a WHERE id = :BC.getJobId()];//get the job Id
      System.debug('$$$ Jobid is'+BC.getJobId());

     //below code will send an email to User about the status
      mail.setToAddresses(email);
      mail.setReplyTo('[email protected]');//Add here your email address
      mail.setSenderDisplayName('Apex Batch Processing Module');
      mail.setSubject('Batch Processing '+a.Status);
      mail.setPlainTextBody('The Batch Apex job processed'
         + a.TotalJobItems+'batches with '+a.NumberOfErrors+'failures'+'Job Item
      processed are'+a.JobItemsProcessed);
      Messaging.sendEmail(new Messaging.Singleemailmessage [] {mail});
   }

  //Scheduler Method to scedule the class
   global void execute(SchedulableContext sc) {
      CustomerProessingBatch conInstance = new CustomerProessingBatch();
      database.executebatch(conInstance,100);
   }
}

//Paste in Developer Console
CustomerProessingBatch objClass = new CustomerProcessingBatch();
Database.executeBatch (objClass);

Apex-デバッグ

デバッグは、プログラミング開発の重要な部分です。 Apexには、デバッグに使用できる特定のツールがあります。 それらの1つは、変数の値と出力をデバッグログに出力するsystem.debug()メソッドです。

デバッグには次の2つのツールを使用できます-

  • 開発者コンソール
  • デバッグログ

開発者コンソールを介したデバッグ

開発者コンソールを使用して、以下のようにApexをデバッグするための匿名機能を実行できます-

今日作成された顧客レコードを取得する既存の例を考えてみましょう。 クエリが結果を返しているかどうかを知りたいだけで、そうであれば、Listの値をチェックします。

匿名ウィンドウの実行に以下のコードを貼り付け、匿名ウィンドウを開くために行った手順に従います。

  • ステップ1 *-開発者コンソールを開きます
  • ステップ2 *-以下に示すように、「デバッグ」から匿名実行を開きます。

クラス実行ステップ1の開発者コンソールを開く

  • ステップ3 *-匿名実行ウィンドウを開き、次のコードを貼り付けて実行をクリックします。

クラス実行ステップ2の開発者コンソールを開く

//Debugging The Apex
List<apex_customer__c> customerList = new List<apex_customer__c>();
customerList = [SELECT Id, Name FROM APEX_Customer__c WHERE CreatedDate =
today];
//Our Query
System.debug('Records on List are '+customerList+' And Records are '+customerList);
//Debug statement to check the value of List and Size
  • ステップ4 *-以下に示すようにログを開きます。

Apex Debugging Devconsole Step1

  • ステップ5 *-以下に示すように、フィルター条件に「USER」と入力します。

画像:[画像]

  • ステップ6 *-以下に示すように、USER DEBUGステートメントを開きます。

画像:[画像]

デバッグログを介したデバッグ

デバッグログを介して同じクラスをデバッグすることもできます。 あなたはCustomerオブジェクトにトリガーがあり、いくつかの変数値についてデバッグする必要があると仮定し、次に示すようにデバッグログを介してこれを行うことができます-

これは、変更された顧客がアクティブで、現在スコープ内の変数とレコードの値を確認したい場合に説明フィールドを更新するトリガーコードです-

trigger CustomerTrigger on APEX_Customer__c (before update) {
   List<apex_customer__c> customerList = new List<apex_customer__c>();
   for (APEX_Customer__c objCust: Trigger.new) {
      System.debug('objCust current value is'+objCust);

      if (objCust.APEX_Active__c == true) {
         objCust.APEX_Customer_Description__c = 'updated';
         System.debug('The record which has satisfied the condition '+objCust);
      }
   }
}

デバッグログを生成するには、以下の手順に従ってください。

  • ステップ1 *-ユーザーのデバッグログを設定します。 [設定]に移動し、検索設定ウィンドウに「デバッグログ」と入力して、[リンク]をクリックします。

Debug Console Step1を介したデバッグ

  • ステップ2 *-デバッグログを次のように設定します。

Debug Console Step2を介したデバッグ

Debug Console Step3を介したデバッグ

  • ステップ3 *-セットアップが必要なユーザーの名前を入力します。 ここに名前を入力してください。

Debug Console Step4を介したデバッグ

  • ステップ4 *-デバッグログを生成するイベントの発生に応じて、顧客レコードを変更します。

Debug Console Step5を介したデバッグ

  • ステップ5 *-デバッグログセクションに再度移動します。 デバッグログを開き、[リセット]をクリックします。

Debug Console Step6を介したデバッグ

  • ステップ6 *-最初のデバッグログの表示リンクをクリックします。

Debug Console Step7を介したデバッグ

  • ステップ7 *-以下に示すブラウザ検索を使用して、文字列「USER」を検索します。

Debug Console Step8を介したデバッグ

デバッグステートメントは、ポイントを設定したフィールドの値を表示します。

Apex-テスト

テストは、Apexまたはその他のアプリケーション開発の統合された部分です。 Apexには、すべてのユニットテスト用に開発する個別のテストクラスがあります。

テストクラス

SFDCでは、実稼働環境に展開するためにコードのコードカバレッジが75%でなければなりません。 このコードカバレッジは、テストクラスによって実行されます。 テストクラスは、他のApexクラスの機能をテストするコードスニペットです。

以前に記述したコードの1つのテストクラスを記述しましょう。 トリガークラスとヘルパークラスのコードをカバーするテストクラスを作成します。 以下は、カバーする必要があるトリガーおよびヘルパークラスです。

//Trigger with Helper Class
trigger Customer_After_Insert on APEX_Customer__c (after update) {
   CustomerTriggerHelper.createInvoiceRecords(Trigger.new, trigger.oldMap);
     //Trigger calls the helper class and does not have any code in Trigger
}

//Helper Class:
public class CustomerTriggerHelper {
   public static void createInvoiceRecords (List<apex_customer__c>

      customerList, Map<id, apex_customer__c> oldMapCustomer) {
      List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();

      for (APEX_Customer__c objCustomer: customerList) {
         if (objCustomer.APEX_Customer_Status__c == 'Active' &&
            oldMapCustomer.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {

           //condition to check the old value and new value
            APEX_Invoice__c objInvoice = new APEX_Invoice__c();
            objInvoice.APEX_Status__c = 'Pending';
            objInvoice.APEX_Customer__c = objCustomer.id;
            InvoiceList.add(objInvoice);
         }
      }
      insert InvoiceList; //DML to insert the Invoice List in SFDC
   }
}

テストクラスの作成

このセクションでは、テストクラスを作成する方法を理解します。

データ作成

テストクラス自体にテストクラスのデータを作成する必要があります。 デフォルトでは、テストクラスは組織データにアクセスできませんが、@ isTest(seeAllData = true)を設定すると、組織のデータにもアクセスできるようになります。

@isTestアノテーション

このアノテーションを使用して、これはテストクラスであり、組織の合計コード制限に対してカウントされないことを宣言しました。

testMethodキーワード

ユニットテストメソッドは、引数を取らず、データベースにデータをコミットせず、電子メールを送信せず、メソッド定義でtestMethodキーワードまたはisTestアノテーションで宣言されているメソッドです。 また、テストクラス、つまりisTestアノテーションが付けられたクラスでテストメソッドを定義する必要があります。

例では「myUnitTest」テストメソッドを使用しました。

Test.startTest()およびTest.stopTest()

これらは、テストクラスで使用できる標準のテストメソッドです。 これらのメソッドには、テストをシミュレートするイベントまたはアクションが含まれています。 この例のように、トリガーとヘルパークラスをテストして、ブロックを開始および停止するために行ったようにレコードを更新することにより、起動トリガーをシミュレートします。 また、これにより、開始ブロックと停止ブロックにあるコードに個別のガバナー制限が提供されます。

System.assert()

このメソッドは、実際の目的の出力をチェックします。 この場合、請求書レコードが挿入されることを想定しているため、同じことを確認するためにassertを追加しました。

/**
* This class contains unit tests for validating the behavior of Apex classes
* and triggers.
*
* Unit tests are class methods that verify whether a particular piece
* of code is working properly. Unit test methods take no arguments,
* commit no data to the database, and are flagged with the testMethod
* keyword in the method definition.
*
* All test methods in an organization are executed whenever Apex code is deployed
* to a production organization to confirm correctness, ensure code
* coverage, and prevent regressions. All Apex classes are
* required to have at least 75% code coverage in order to be deployed
* to a production organization. In addition, all triggers must have some code coverage.
*
* The @isTest class annotation indicates this class only contains test
* methods. Classes defined with the @isTest annotation do not count against
* the organization size limit for all Apex scripts.
*
* See the Apex Language Reference for more information about Testing and Code Coverage.
*/

@isTest
private class CustomerTriggerTestClass {
   static testMethod void myUnitTest() {
     //Create Data for Customer Objet
      APEX_Customer__c objCust = new APEX_Customer__c();
      objCust.Name = 'Test Customer';
      objCust.APEX_Customer_Status__c = 'Inactive';
      insert objCust;

     //Now, our trigger will fire on After update event so update the Records
      Test.startTest();   //Starts the scope of test
      objCust.APEX_Customer_Status__c = 'Active';
      update objCust;
      Test.stopTest();    //Ends the scope of test

     //Now check if it is giving desired results using system.assert
     //Statement.New invoice should be created
      List<apex_invoice__c> invList = [SELECT Id, APEX_Customer__c FROM
         APEX_Invoice__c WHERE APEX_Customer__c = :objCust.id];
      system.assertEquals(1,invList.size());
     //Check if one record is created in Invoivce sObject
   }
}

テストクラスの実行

テストクラスを実行するには、以下の手順に従ってください-

  • ステップ1 *-Apexクラスに移動⇒クラス名「CustomerTriggerTestClass」をクリックします。
  • ステップ2 *-図のように[テストの実行]ボタンをクリックします。

頂点テストステップ1

  • ステップ3 *-ステータスを確認する

Apex Testing Step2

  • ステップ4 *-テストを作成したクラスとトリガーを確認します

クラス

Apex Testing Step3

引き金

Apex Testing Step4

テストは成功して完了しました。

Apex-展開

SFDCでの展開とは何ですか?

これまではDeveloper Editionでコードを開発しましたが、実際のシナリオでは、Sandboxでこの開発を行う必要があり、その後、これを別のSandboxまたは運用環境に展開する必要があります。これは展開と呼ばれます。 つまり、これは、ある組織から別の組織へのメタデータの移動です。 この背後にある理由は、Salesforce本番組織でApexを開発できないことです。 開発中にライブユーザーがシステムにアクセスすると、データが不安定になったり、アプリケーションが破損したりする可能性があります。

展開プロセス

展開に利用できるツール-

  • Force.com IDE
  • 変更セット
  • SOAP API
  • Force.com移行ツール

開発および学習の目的でDeveloper Editionを使用しているため、SFDCエンタープライズまたはその他の有料版を必要とする変更セットまたはその他のツールは使用できません。 したがって、このチュートリアルではForce.com IDEの展開方法について詳しく説明します。

Force.com Eclipse IDE

  • ステップ1 *-Eclipseを開き、デプロイする必要のあるクラストリガーを開きます。

Eclipse Process Step1

  • ステップ2 *-[サーバーにデプロイ]をクリックすると、コンポーネントのデプロイが必要な組織のユーザー名とパスワードを入力します。

Eclipse Process Step2

上記の手順を実行すると、Apexコンポーネントがターゲット組織に展開されます。

変更セットを使用した展開

検証設定、ワークフロールール、Apexクラス、およびトリガーをある組織から別の組織にデプロイするには、それらをデプロイ設定で接続します。 この場合、組織は接続されている必要があります。

展開セットアップを開くには、以下の手順に従います。 この機能はDeveloper Editionでは利用できないことに注意してください-

  • ステップ1 *-[セットアップ]に移動し、[展開]を検索します。
  • ステップ2 *-「アウトバウンド変更セット」をクリックして、展開する変更セットを作成します。
  • ステップ3 *-[追加]ボタンを使用して変更セットにコンポーネントを追加し、[保存]をクリックして[アップロード]をクリックします。
  • ステップ4 *-ターゲット組織に移動し、インバウンド変更セットをクリックして、最後にデプロイをクリックします。

デプロイするSOAP API呼び出し

これは一般的に使用される方法ではないため、この方法の概要を簡単に説明します。

以下に示すメソッド呼び出しを使用して、メタデータをデプロイできます。

  • compileAndTest()
  • compileClasses()
  • compileTriggers()

Force.com移行ツール

このツールは、スクリプト化された展開に使用されます。 Force.com移行ツールをダウンロードしてから、ファイルベースの展開を実行できます。 Force.com移行ツールをダウンロードしてから、スクリプト展開を実行できます。