Apex-クイックガイド
Apexとは何ですか?
Apexは、Salesforce.comによって開発された独自の言語です。公式の定義によると、Apexは強く型付けされたオブジェクト指向プログラミング言語であり、開発者はForce.comAPIの呼び出しと組み合わせてForce.comプラットフォームサーバーでフローおよびトランザクション制御ステートメントを実行できます。
Javaに似た構文を持ち、データベースのストアドプロシージャのように機能します。これにより、開発者は、ボタンのクリック、関連するレコードの更新、Visualforceなど、ほとんどのシステムイベントにビジネスロジックを追加できます。pages.Apexコードは、Webサービス要求およびオブジェクトのトリガーから開始できます。Apexは、Performance Edition、Unlimited Edition、Enterprise Edition、およびDeveloperEditionに含まれています。
言語としての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は、事前に構築された既存の機能を使用して複雑なビジネス機能を実装できない場合に使用する必要があります。以下は、Salesforce構成ではなくapexを使用する必要がある場合です。
Apexアプリケーション
必要なときにApexを使用できます-
他のシステムを統合してWebサービスを作成します。
メールブラストまたはメール設定用のメールサービスを作成します。
複数のオブジェクトに対して同時に複雑な検証を実行し、カスタム検証の実装も実行します。
既存のワークフロー機能またはフローではサポートされていない複雑なビジネスプロセスを作成します。
レコードを更新するためにデータベースメソッドを使用するように、カスタムトランザクションロジック(単一のレコードまたはオブジェクトだけでなく、トランザクション全体で発生するロジック)を作成します。
レコードが変更されたときにロジックを実行するか、トリガーを起動する原因となったイベントがあるときに関連オブジェクトのレコードを変更します。
Apexの動作構造
次の図(参照:Salesforce開発者ドキュメント)に示すように、Apexは完全にオンデマンドで実行されますForce.comプラットフォーム
アクションの流れ
開発者がコードを保存するときと、エンドユーザーが以下に示すようにApexコードを呼び出すアクションを実行するときの2つのアクションシーケンスがあります。
開発者アクション
開発者がApexコードを記述してプラットフォームに保存すると、プラットフォームアプリケーションサーバーは最初にコードをApexランタイムインタープリターが理解できる一連の命令にコンパイルし、次にそれらの命令をメタデータとして保存します。
エンドユーザーアクション
エンドユーザーがボタンをクリックするかVisualforceページにアクセスすることにより、Apexの実行をトリガーすると、プラットフォームアプリケーションサーバーは、メタデータからコンパイルされた命令を取得し、結果を返す前にランタイムインタープリターに送信します。エンドユーザーは、標準のアプリケーションプラットフォーム要求と比較して実行時間に違いはありません。
ApexはSalesforce.comの独自言語であるため、一般的なプログラミング言語がサポートする一部の機能をサポートしていません。以下は、Apexがサポートしていないいくつかの機能です-
ユーザーインターフェイスに要素を表示することはできません。
標準のSFDCが提供する機能を変更することはできません。また、標準の機能の実行を妨げることもできません。
他の言語で作成できるため、複数のスレッドを作成することもできません。
Apex構文を理解する
Apexコードには通常、他のプログラミング言語でおなじみの多くのものが含まれています。
変数宣言
強く型付けされた言語として、Apexでデータ型を持つすべての変数を宣言する必要があります。以下のコード(以下のスクリーンショット)に見られるように、lstAccはアカウントのリストとしてデータ型で宣言されています。
SOQLクエリ
これは、Salesforceデータベースからデータをフェッチするために使用されます。以下のスクリーンショットに示されているクエリは、Accountオブジェクトからデータをフェッチしています。
ループステートメント
このループステートメントは、リストを反復処理したり、コードの一部を指定された回数だけ反復処理したりするために使用されます。以下のスクリーンショットに示されているコードでは、反復はレコードの数と同じになります。
フロー制御ステートメント
このコードでは、フロー制御にIfステートメントが使用されています。特定の条件に基づいて、実行に進むか、特定のコードの実行を停止するかが決定されます。たとえば、以下に示すコードでは、リストが空であるか、レコードが含まれているかをチェックしています。
DMLステートメント
データベース内のレコードに対して、レコードの挿入、更新、アップサート、削除操作を実行します。たとえば、以下のコードは、新しいフィールド値でアカウントを更新するのに役立ちます。
以下は、Apexコードスニペットがどのように表示されるかの例です。このチュートリアルでは、これらすべてのApexプログラミングの概念についてさらに学習します。
この章では、SalesforceApex開発の環境について理解します。Apex開発を行うためにSalesforceエディションがすでに設定されていることを前提としています。
Apexコードは、Salesforceのサンドボックス版または開発者版のいずれかで開発できます。サンドボックス組織は、データの変更や通常の機能の妨害のリスクを冒すことなく、コードを記述してテストできる組織のコピーです。標準的な産業慣行に従って、サンドボックスでコードを開発してから、本番環境にデプロイする必要があります。
このチュートリアルでは、SalesforceのDeveloperエディションを使用します。Developerエディションでは、サンドボックス組織を作成するオプションはありません。サンドボックス機能は、Salesforceの他のエディションで使用できます。
Apexコード開発ツール
すべてのエディションで、次の3つのツールのいずれかを使用してコードを開発できます-
- Force.com開発者コンソール
- Force.com IDE
- Salesforceユーザーインターフェイスのコードエディタ
Note − チュートリアル全体を通して、コードの実行に開発者コンソールを利用します。これは、学習が簡単でユーザーフレンドリーであるためです。
Force.com開発者コンソール
開発者コンソールは、Salesforce組織でアプリケーションを作成、デバッグ、およびテストするために使用できるツールのコレクションを備えた統合開発環境です。
次の手順に従って、開発者コンソールを開きます-
Step 1 − 名前→開発者コンソールに移動します
Step 2 − 「開発者コンソール」をクリックすると、次のスクリーンショットのようなウィンドウが表示されます。
以下は、開発者コンソールを使用して実行できるいくつかの操作です。
Writing and compiling code −ソースコードエディタを使用してコードを記述できます。トリガーまたはクラスを保存すると、コードは自動的にコンパイルされます。コンパイルエラーがあれば報告されます。
Debugging −ソースコードエディタを使用してコードを記述できます。トリガーまたはクラスを保存すると、コードは自動的にコンパイルされます。コンパイルエラーがあれば報告されます。
Testing − デバッグログを表示し、デバッグに役立つチェックポイントを設定できます。
Checking performance −特定のテストクラスまたは組織内のすべてのクラスのテストを実行し、テスト結果を表示できます。また、コードカバレッジを検査することもできます。
SOQL queries − デバッグログを調べて、パフォーマンスのボトルネックを見つけることができます。
Color coding and autocomplete − ソースコードエディタは、コード要素を読みやすくするために配色を使用し、クラス名とメソッド名のオートコンプリートを提供します。
開発者コンソールでのコードの実行
このチュートリアルで説明されているすべてのコードスニペットは、開発者コンソールで実行する必要があります。開発者コンソールで手順を実行するには、次の手順に従います。
Step 1 −を使用してSalesforce.comにログインします login.salesforce.com。チュートリアルに記載されているコードスニペットをコピーします。今のところ、次のサンプルコードを使用します。
String myString = 'MyString';
System.debug('Value of String Variable'+myString);
Step 2 −開発者コンソールを開くには、以下に示すように、[名前]→[開発者コンソール]をクリックしてから、[匿名の実行]をクリックします。
Step 3 −このステップでは、ウィンドウが表示され、そこにコードを貼り付けることができます。
Step 4 −をクリックすると Execute、デバッグログが開きます。以下に示すようにログがウィンドウに表示されたら、ログレコードをクリックします。
次に、以下に示すようにウィンドウに「USER」と入力すると、出力ステートメントがデバッグウィンドウに表示されます。この「USER」ステートメントは、出力のフィルタリングに使用されます。
したがって、基本的には、上記のすべての手順に従って、このチュートリアルのコードスニペットを実行します。
エンタープライズアプリケーション開発の例
このチュートリアルでは、化学機器および処理会社のCRMアプリケーションを実装します。この会社はサプライヤーと取引し、サービスを提供しています。チュートリアル全体を通して、この例に関連する小さなコードスニペットを作成して、すべての概念を詳細に理解します。
このチュートリアルのコードを実行するには、CustomerオブジェクトとInvoiceオブジェクトの2つのオブジェクトを作成する必要があります。Salesforceでこれらのオブジェクトを作成する方法をすでに知っている場合は、以下の手順をスキップできます。それ以外の場合は、以下のステップバイステップガイドに従うことができます。
顧客オブジェクトの作成
最初にCustomerオブジェクトを設定します。
Step 1−セットアップに移動し、次に示すように「オブジェクト」を検索します。次に、以下に示すように、[オブジェクト]リンクをクリックします。
Step 2 −オブジェクトページが開いたら、「」をクリックします。Create New Object以下に示すように 'ボタン。
Step 3−ボタンをクリックすると、新しいオブジェクト作成ページが表示され、以下に入力するようにすべてのオブジェクトの詳細を入力します。オブジェクト名はCustomerである必要があります。以下のスクリーンショットに示すように、フィールドに情報を入力し、他のデフォルトのものをそのままにしておく必要があります。
情報を入力し、[保存]ボタンをクリックします-
上記の手順に従うことで、Customerオブジェクトが正常に作成されました。
Customerオブジェクトのカスタムフィールドの作成
Customerオブジェクトを設定したので、フィールド「アクティブ」を作成します。次に、同様の手順に従って他のフィールドを作成できます。フィールドの名前とAPI名はスクリーンショットに表示されます。
Step 1−チェックボックスとしてデータ型の「アクティブ」という名前のフィールドを作成します。セットアップに移動してクリックします。
Step 2 −以下に示すように「オブジェクト」を検索し、クリックします。
Step 3 −オブジェクト「顧客」をクリックします。
Step 4 − [顧客オブジェクト]リンクをクリックしてオブジェクトの詳細ページが表示されたら、[新規]ボタンをクリックします。
Step 5 −ここで、チェックボックスとしてデータ型を選択し、[次へ]をクリックします。
Step 6 −以下に示すように、フィールド名とラベルを入力します。
Step 7 − [表示]をクリックしてから、[次へ]をクリックします。
Step 8 − [保存]をクリックします。
上記の手順に従うことにより、カスタムフィールド「アクティブ」が作成されます。残りのフィールドについては、上記のすべてのカスタムフィールド作成手順に従う必要があります。これは、すべてのフィールドが作成された後の顧客オブジェクトの最終ビューです-
請求書オブジェクトの作成
Step 1 − [設定]に移動して[オブジェクト]を検索し、次に示すように[オブジェクト]リンクをクリックします。
Step 2 −オブジェクトページが開いたら、次に示すように[新しいオブジェクトの作成]ボタンをクリックします。
Step 3−ボタンをクリックすると、下のスクリーンショットに示すように、新しいオブジェクト作成ページが表示されます。ここに詳細を入力する必要があります。オブジェクト名はInvoiceである必要があります。これは、このチュートリアルの前半でCustomerオブジェクトを作成した方法と似ています。
Step 4 −以下のように情報を入力し、「保存」ボタンをクリックします。
これらの手順に従うと、請求書オブジェクトが作成されます。
請求書オブジェクトのカスタムフィールドの作成
以下に示すように、請求書オブジェクトにフィールド説明を作成します-
Step 1 − [設定]に移動してクリックします。
Step 2 −以下に示すように「オブジェクト」を検索し、クリックします。
Step 3 −オブジェクト「請求書」をクリックします。
次に、[新規]をクリックします。
Step 4 −データ型をテキスト領域として選択し、[次へ]ボタンをクリックします。
Step 5 −以下の情報を入力してください。
Step 6 − [表示]、[次へ]の順にクリックします。
Step 7 − [保存]をクリックします。
同様に、Invoiceオブジェクトに他のフィールドを作成できます。
これにより、このチュートリアルに必要なオブジェクトを作成しました。これらのオブジェクトに基づいて、次の章でさまざまな例を学習します。
データ型を理解する
Apex言語は強く型付けされているため、Apexのすべての変数は特定のデータ型で宣言されます。すべての頂点変数は、最初はnullに初期化されます。開発者は、変数に適切な値が割り当てられていることを確認することを常にお勧めします。それ以外の場合、このような変数を使用すると、nullポインター例外または未処理の例外がスローされます。
Apexは次のデータ型をサポートしています-
プリミティブ(整数、倍精度、長整数、日付、日時、文字列、ID、またはブール値)
コレクション(リスト、セット、マップ)(第6章で説明)
sObject
Enums
クラス、オブジェクト、およびインターフェイス(第11章、第12章、および第13章で説明します)
この章では、すべてのプリミティブデータ型、sObject、および列挙型について説明します。コレクション、クラス、オブジェクト、およびインターフェイスは、個別に学習する重要なトピックであるため、次の章で説明します。
プリミティブデータ型
このセクションでは、Apexでサポートされているプリミティブデータ型について説明します。
整数
小数点を含まない32ビットの数値。この値の範囲は-2,147,483,648から始まり、最大値は最大2,147,483,647です。
Example
化学処理プラントのバイヤーに出荷する必要のあるバレルの数量を格納する変数を宣言したいと思います。
Integer barrelNumbers = 1000;
system.debug(' value of barrelNumbers variable: '+barrelNumbers);
ザ・ System.debug() 関数は変数の値を出力するので、これを使用してデバッグしたり、変数が現在保持している値を知ることができます。
上記のコードを開発者コンソールに貼り付け、[実行]をクリックします。ログが生成されると、変数「barrelNumbers」の値が1000として表示されます。
ブール値
この変数は、true、false、またはnullのいずれかになります。多くの場合、このタイプの変数は、特定の条件が設定されているかどうかを識別するためのプログラミングのフラグとして使用できます。
Example
ブールshipmentDispatchedをtrueに設定する場合は、次のように宣言できます。
Boolean shipmentDispatched;
shipmentDispatched = true;
System.debug('Value of shipmentDispatched '+shipmentDispatched);
日付
この変数タイプは日付を示します。これは日付のみを保存でき、時刻は保存できません。日付を時間とともに保存するには、DateTimeの変数に保存する必要があります。
Example
次の例を検討して、Date変数がどのように機能するかを理解してください。
//ShipmentDate can be stored when shipment is dispatched.
Date ShipmentDate = date.today();
System.debug('ShipmentDate '+ShipmentDate);
長いです
これは、小数点のない64ビットの数値です。これは、整数によって提供される値よりも広い値の範囲が必要な場合に使用されます。
Example
会社の収益を保存する場合は、データ型をLongとして使用します。
Long companyRevenue = 21474838973344648L;
system.debug('companyRevenue'+companyRevenue);
オブジェクト
これは、Apexでサポートされている任意のデータ型と呼ぶことができます。たとえば、クラス変数はそのクラスのオブジェクトであり、sObjectジェネリック型もオブジェクトであり、Accountなどの同様に特定のオブジェクト型もオブジェクトです。
Example
次の例を検討して、bject変数がどのように機能するかを理解してください。
Account objAccount = new Account (Name = 'Test Chemical');
system.debug('Account value'+objAccount);
Note −以下に示すように、事前定義されたクラスのオブジェクトを作成することもできます。
//Class Name: MyApexClass
MyApexClass classObj = new MyApexClass();
これは、クラス変数として使用されるクラスオブジェクトです。
ストリング
文字列は、一重引用符で囲まれた文字のセットです。文字数に制限はありません。ここでは、ヒープサイズを使用して文字数を決定します。これにより、Apexプログラムによるリソースの独占が抑制され、リソースが大きくなりすぎないようになります。
Example
String companyName = 'Abc International';
System.debug('Value companyName variable'+companyName);
時間
この変数は、特定の時間を格納するために使用されます。この変数は、常にシステム静的メソッドで宣言する必要があります。
ブロブ
Blobは、オブジェクトとして保存されるバイナリデータのコレクションです。これは、Salesforceの添付ファイルを変数に保存する場合に使用されます。このデータ型は、添付ファイルを単一のオブジェクトに変換します。blobを文字列に変換する場合は、toStringメソッドとvalueOfメソッドを使用できます。
sObject
これはSalesforceの特別なデータ型です。これはSQLのテーブルに似ており、SQLの列に似たフィールドが含まれています。sObjectには、標準とカスタムの2種類があります。
たとえば、Accountは標準のsObjectであり、その他のユーザー定義オブジェクト(作成したCustomerオブジェクトなど)はカスタムsObjectです。
Example
//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);
列挙型
列挙型は、指定された識別子の有限セットの1つの値を格納する抽象データ型です。キーワードEnumを使用して、Enumを定義できます。列挙型は、Salesforceの他のデータ型と同じように使用できます。
Example
次のコードを実行することにより、化合物の可能な名前を宣言できます。
//Declaring enum for Chemical Compounds
public enum Compounds {HCL, H2SO4, NACL, HG}
Compounds objC = Compounds.HCL;
System.debug('objC value: '+objC);
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が割り当てられていることに注意してください。
Declaring Variables
文字列や整数などの変数をApexで次のように宣言できます-
String strName = 'My String'; //String variable declaration
Integer myInteger = 1; //Integer variable declaration
Boolean mtBoolean = true; //Boolean variable declaration
Apex variables are Case-Insensitive
これは、変数 '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');
}
Scope of Variables
Apex変数は、コードで宣言された時点から有効です。したがって、同じ変数をコードブロックで再定義することはできません。また、メソッドで変数を宣言すると、その変数のスコープはその特定のメソッドのみに制限されます。ただし、クラス変数にはクラス全体でアクセスできます。
Example
//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の文字列は、他のプログラミング言語と同様に、文字数制限のない任意の文字セットです。
Example
String companyName = 'Abc International';
System.debug('Value companyName variable'+companyName);
文字列メソッド
Salesforceの文字列クラスには多くのメソッドがあります。この章では、最も重要で頻繁に使用される文字列メソッドのいくつかを見ていきます。
含まれています
指定された文字列に指定された部分文字列が含まれている場合、このメソッドはtrueを返します。
Syntax
public Boolean contains(String substring)
Example
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を比較することもできます。この方法では大文字と小文字が区別されます。
Syntax
public Boolean equals(Object string)
Example
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を返します。ただし、この方法では大文字と小文字は区別されません。
Syntax
public Boolean equalsIgnoreCase(String stringtoCompare)
Example
次のコードは、大文字と小文字の区別を無視して、文字列文字とシーケンスが同じであるため、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で指定された文字列を指定された文字列から削除します。これは、文字列から特定の文字を削除する必要があり、削除する文字の正確なインデックスがわからない場合に役立ちます。この方法では大文字と小文字が区別され、同じ文字シーケンスが発生しても大文字と小文字が異なる場合は機能しません。
Syntax
public String remove(String stringToRemove)
Example
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で指定された文字列を指定された文字列から削除しますが、それが最後に発生した場合に限ります。この方法では大文字と小文字は区別されません。
Syntax
public String removeEndIgnoreCase(String stringToRemove)
Example
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);
startWith
指定された文字列がメソッドで指定されたプレフィックスで始まる場合、このメソッドはtrueを返します。
Syntax
public Boolean startsWith(String prefix)
Example
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のリストと同じです。配列とリストの内部データ構造とメソッドも同じであるため、論理的な違いはありませんが、配列の構文はJavaのように少し伝統的です。
以下は、製品の配列の表現です-
Index 0 − HCL
Index 1 − H2SO4
Index 2 − NACL
Index 3 − H2O
Index 4 − n2
Index 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では、定数は、プログラムの実行全体で一定の値を持つ必要がある変数を定義する場合に使用されます。頂点定数は、キーワード「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);
意思決定構造では、プログラマーは、プログラムによって評価またはテストされる1つ以上の条件と、条件が真であると判断された場合に実行される1つまたは複数のステートメント、およびオプションで、条件はfalseと判断されます。
この章では、Apexの意思決定と条件文の基本構造と高度な構造について学習します。特定の条件が満たされた場合、または満たされない場合の実行フローを制御するには、意思決定が必要です。以下は、ほとんどのプログラミング言語に見られる典型的な意思決定構造の一般的な形式です。
シニア番号 | ステートメントと説明 |
---|---|
1 | ifステートメント ifステートメントは、ブール式とそれに続く1つ以上のステートメントで構成されます。 |
2 | if ... elseステートメント ifステートメントの後にオプションのオプションを続けることができます else ブール式がfalseの場合に実行されるステートメント。 |
3 | if ... elseif ... elseステートメント ifステートメントの後にオプションのオプションを続けることができます else if...else ステートメント。これは、単一のif ... elseifステートメントを使用してさまざまな条件をテストするのに非常に役立ちます。 |
4 | ネストされたifステートメント あなたは1つを使用することができます if or else if 別の内部のステートメント if or else if ステートメント。 |
ループは、特定のコードを必要な反復回数で繰り返す必要がある場合に使用されます。Apexは、標準の従来のforループおよびその他の高度なタイプのループをサポートします。この章では、Apexのループについて詳しく説明します。
ループステートメントを使用すると、ステートメントまたはステートメントのグループを複数回実行できます。以下は、ほとんどのプログラミング言語でのループステートメントの一般的なfromです。
次の表に、Apexプログラミング言語でループ要件を処理するさまざまなループを示します。詳細を確認するには、次のリンクをクリックしてください。
シニア番号 | ループの種類と説明 |
---|---|
1 | forループ このループは、一連のレコード内の各アイテムに対して一連のステートメントを実行します。 |
2 | SOQLforループ 返されたセットoSOQLクエリに対して直接ステートメントのシーケンスを実行します。 |
3 | Javaのようなforループ 従来のJavaのような構文で一連のステートメントを実行します。 |
4 | whileループ 指定された条件が真である間、ステートメントまたはステートメントのグループを繰り返します。ループ本体を実行する前に条件をテストします。 |
5 | do ... whileループ whileステートメントと同様ですが、ループ本体の最後で条件をテストする点が異なります。 |
コレクションは、複数のレコードを格納できる変数の一種です。たとえば、Listには複数のAccountオブジェクトのレコードを保存できます。ここで、すべてのコレクションタイプの詳細な概要を見てみましょう。
リスト
リストには、プリミティブ、コレクション、sObject、ユーザー定義、および組み込みのApexタイプのレコードをいくつでも含めることができます。これは最も重要なタイプのコレクションの1つであり、Listで使用するために特別に調整されたいくつかのシステムメソッドがあります。リストインデックスは常に0で始まります。これはJavaの配列と同義です。リストは、キーワード「リスト」で宣言する必要があります。
Example
以下は、プリミティブデータ型(文字列)のリスト、つまり都市のリストを含むリストです。
List<string> ListOfCities = new List<string>();
System.debug('Value Of ListOfCities'+ListOfCities);
リストの初期値の宣言はオプションです。ただし、ここで初期値を宣言します。以下は同じことを示す例です。
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);
リストには任意の数のレコードを含めることができますが、パフォーマンスの問題を防ぎ、リソースを独占するために、ヒープサイズに制限があります。
リストのメソッド
リストのサイズの計算、要素の追加などのいくつかの機能を実現するためにプログラミング中に利用できるリストに使用できるメソッドがあります。
以下は、最も頻繁に使用されるいくつかの方法です-
- size()
- add()
- get()
- clear()
- set()
次の例は、これらすべての方法の使用法を示しています
// 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>();
セット
セットは、複数の順序付けされていない一意のレコードを含むコレクションタイプです。セットに重複するレコードを含めることはできません。リストと同様に、セットはネストできます。
Example
会社が販売している製品のセットを定義します。
Set<string> ProductSet = new Set<string>{'Phenol', 'Benzene', 'H2SO4'};
System.debug('Value of ProductSet'+ProductSet);
セットのメソッド
Setは、以下に示すようにプログラミング中に利用できるメソッドをサポートします(上記の例を拡張しています)-
// 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);
マップ
これは、各値の一意のキーを含むキーと値のペアです。キーと値はどちらも任意のデータ型にすることができます。
Example
次の例は、製品名と製品コードのマップを表しています。
// 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);
マップ値は順序付けられていない可能性があるため、値が格納されている順序に依存せず、常にキーを使用してマップにアクセスしようとしないでください。マップ値はnullにすることができます。Stringが宣言されている場合のマップキーでは、大文字と小文字が区別されます。たとえば、ABCとabcは異なるキーと見なされ、一意として扱われます。
クラスとは何ですか?
クラスは、オブジェクトの作成元となるテンプレートまたは青写真です。オブジェクトはクラスのインスタンスです。これはクラスの標準的な定義です。ApexクラスはJavaクラスに似ています。
例えば、 InvoiceProcessorclassは、請求書で実行できるすべてのメソッドとアクションを含むクラスを記述します。このクラスのインスタンスを作成すると、現在コンテキストにある単一の請求書が表されます。
クラスの作成
Apexでクラスを作成するには、開発者コンソール、Force.com Eclipse IDE、およびApexクラスの詳細ページからも使用できます。
開発者コンソールから
次の手順に従って、開発者コンソールからApexクラスを作成します-
Step 1 − [名前]に移動し、開発者コンソールをクリックします。
Step 2 − [ファイル]⇒[新規]をクリックしてから、Apexクラスをクリックします。
Force.comIDEから
次の手順に従って、Force.comIDEからクラスを作成します-
Step 1 − Force.com EclipseIDEを開きます
Step 2 − [ファイル]⇒[新規]⇒[Apexクラス]をクリックして、新しいプロジェクトを作成します。
Step 3 −クラスの名前を入力し、[OK]をクリックします。
これが完了すると、新しいクラスが作成されます。
Apexクラスの詳細ページから
次の手順に従って、Apexクラス詳細ページからクラスを作成します-
Step 1 − [名前]⇒[設定]をクリックします。
Step 2−「ApexClass」を検索し、リンクをクリックします。Apexクラスの詳細ページが開きます。
Step 3 − [新規]をクリックし、クラスの名前を入力して、[保存]をクリックします。
Apexクラス構造
以下は、Apexクラス定義のサンプル構造です。
Syntax
private | public | global
[virtual | abstract | with sharing | without sharing]
class ClassName [implements InterfaceNameList] [extends ClassName] {
// Classs Body
}
この定義では、アクセス修飾子、共有モード、クラス名、およびクラス本体の組み合わせを使用します。これらすべてのオプションについてさらに詳しく見ていきます。
Example
以下は、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クラスの特別な機能です。クラスが「WithSharing」キーワードで指定されている場合、次の意味があります。クラスが実行されると、ユーザーのアクセス設定とプロファイル権限が尊重されます。ユーザーのアクションによって30レコードのレコード更新がトリガーされたが、ユーザーは20レコードにしかアクセスできず、10レコードにはアクセスできないとします。次に、クラスがレコードを更新するアクションを実行している場合、ユーザーがアクセスできる20レコードのみが更新され、残りの10レコードは更新されません。これは、ユーザーモードとも呼ばれます。
共有せずに
ユーザーが30のうち10のレコードにアクセスできない場合でも、クラスがシステムモードで実行されているため、30のレコードすべてが更新されます。つまり、共有なしのキーワードで定義されています。これはシステムモードと呼ばれます。
バーチャル
'virtual'キーワードを使用すると、このクラスを拡張でき、オーバーライドが許可されることを示します。メソッドをオーバーライドする必要がある場合は、virtualキーワードを使用してクラスを宣言する必要があります。
概要
クラスを「abstract」として宣言すると、メソッドのシグネチャのみが含まれ、実際の実装は含まれません。
クラス変数
Syntax
[public | private | protected | global] [final] [static] data_type
variable_name [= value]
上記の構文では-
- 変数のデータ型と変数名は必須です
- アクセス修飾子と値はオプションです。
Example
public static final Integer myvalue;
クラスメソッド
Apexのクラスメソッドには、パブリックまたはプロテクトの2つの修飾子があります。メソッドには戻り値の型が必須であり、メソッドが何も返さない場合は、戻り値の型としてvoidを指定する必要があります。また、メソッドにはボディも必要です。
Syntax
[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サービスメソッドとして公開できます。
Example
//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として値を割り当てたいとします。
Example
// 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);
コンストラクターのオーバーロード
コンストラクターはオーバーロードできます。つまり、クラスには、異なるパラメーターで定義された複数のコンストラクターを含めることができます。
Example
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);
クラスのインスタンスはObjectと呼ばれます。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の作成
sObjectsは、データを保存する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);
静的初期化
静的メソッドと変数は、クラスがロードされるときに1回だけ初期化されます。静的変数は、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);
Static Variable Use
静的変数は、クラスがロードされたときに1回だけインスタンス化され、この現象を使用してトリガーの再帰を回避できます。静的変数値は同じ実行コンテキスト内で同じであり、実行中のクラス、トリガー、またはコードはそれを参照して再帰を防ぐことができます。
インターフェイスは、どのメソッドも実装されていない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メソッドを実装しないと、エラーがスローされます。開発者にメソッドの実装を必須にする場合は、インターフェイスを使用する必要があります。
BatchApexの標準Salesforceインターフェース
SFDCには、Database.Batchable、Schedulableなどの標準インターフェイスがあります。たとえば、Database.Batchableインターフェイスを実装する場合は、インターフェイスで定義されている3つのメソッド(開始、実行、終了)を実装する必要があります。
以下は、バッチステータスのユーザーにメールを送信する標準のSalesforce提供のDatabase.Batchableインターフェースの例です。このインターフェースには、開始、実行、終了の3つのメソッドがあります。このインターフェイスを使用して、Batchable機能を実装できます。また、実行中のBatchに関する詳細情報を取得したり、他の機能を実行したりするために使用できる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);
この章では、Salesforceでさまざまなデータベース変更機能を実行する方法について説明します。機能を実行できる2つの言い方があります。
DMLステートメント
DMLは、挿入、更新、削除、アップサート、レコードの復元、レコードのマージ、またはリードの変換操作を実行するために実行されるアクションです。
ほとんどすべてのビジネスケースにはデータベースの変更と修正が含まれるため、DMLはApexで最も重要な部分の1つです。
データベースメソッド
DMLステートメントを使用して実行できるすべての操作は、データベースメソッドを使用して実行することもできます。データベースメソッドは、DML操作を実行するために使用できるシステムメソッドです。データベースメソッドは、DMLステートメントと比較してより柔軟性があります。
この章では、DMLステートメントを使用した最初のアプローチについて説明します。次の章でデータベースメソッドを見ていきます。
DMLステートメント
ここで、化学品サプライヤー企業の事例をもう一度考えてみましょう。請求書レコードには、ステータス、支払額、残額、次の支払日、請求書番号などのフィールドがあります。本日作成され、ステータスが「保留中」の請求書は、「支払い済み」に更新する必要があります。
挿入操作
挿入操作は、データベースに新しいレコードを作成するために使用されます。Insert DMLステートメントを使用して、任意の標準オブジェクトまたはカスタムオブジェクトのレコードを作成できます。
Example
新しい顧客の注文に対して新しい請求書が毎日生成されるため、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);
更新操作
更新操作は、既存のレコードに対して更新を実行することです。この例では、既存の請求書レコードのステータスフィールドを「有料」に更新します。
Example
// 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]);
アップサート操作
アップサート操作は更新操作を実行するために使用され、更新されるレコードがデータベースに存在しない場合は、新しいレコードも作成します。
Example
Customerオブジェクトの顧客レコードを更新する必要があるとします。既存の顧客レコードがすでに存在する場合は更新し、存在しない場合は新しいレコードを作成します。これは、フィールドAPEX_External_Id__cの値に基づきます。このフィールドは、レコードがすでに存在するかどうかを識別するためのフィールドになります。
Note −このコードを実行する前に、外部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);
}
}
削除操作
削除DMLを使用して削除操作を実行できます。
Example
この場合、テスト目的で作成された請求書、つまり「テスト」という名前が含まれている請求書を削除します。
このスニペットは、クラスを作成せずに開発者コンソールからも実行できます。
// 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');
元に戻す操作
ごみ箱にある、削除されたレコードの削除を取り消すことができます。削除されたレコードの関係もすべて復元されます。
Example
前の例で削除されたレコードを復元する必要があるとします。これは、次の例を使用して実現できます。前の例のコードは、この例のために変更されています。
// 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');
データベースクラスメソッドは、挿入、更新などのDMLステートメントよりも柔軟なDMLステートメントを操作する別の方法です。
データベースメソッドとDMLステートメントの違い
DMLステートメント | データベースメソッド |
---|---|
部分的な更新は許可されていません。たとえば、リストに20個のレコードがある場合、すべてのレコードが更新されるか、まったく更新されません。 | 部分的な更新が許可されます。データベースメソッドのパラメータをtrueまたはfalseとして指定できます。trueは部分的な更新を許可し、falseは同じものを許可しないようにします。 |
成功したレコードと失敗したレコードのリストを取得することはできません。 | 例で見たように、成功レコードと失敗レコードのリストを取得できます。 |
Example −listNameを挿入 | Example − database.insert(listName、False)。falseは、部分的な更新が許可されていないことを示します。 |
挿入操作
データベースメソッドを介した新しいレコードの挿入も非常に簡単で柔軟です。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());
}
}
}
このチュートリアルでは、挿入操作と更新操作のみを見ていきます。他の操作は、これらの操作と前の章で行ったことと非常によく似ています。
すべてのビジネスまたはアプリケーションには、基本的な要件の1つとして検索機能があります。このため、Salesforce.comは、SOSLとSOQLを使用した2つの主要なアプローチを提供します。この章では、SOSLアプローチについて詳しく説明します。
SOSL
オブジェクト全体およびフィールド全体のテキスト文字列の検索は、SOSLを使用して実行されます。これはSalesforceオブジェクト検索言語です。複数のオブジェクトにわたって特定の文字列を検索する機能があります。
SOSLステートメントはsObjectのリストに評価されます。各リストには、特定のsObjectタイプの検索結果が含まれています。結果リストは、常にSOSLクエリで指定されたのと同じ順序で返されます。
SOSLクエリの例
指定された文字列を検索できるプログラムを開発する必要があるビジネスケースを考えてみましょう。InvoiceオブジェクトのCustomerNameフィールドで文字列「ABC」を検索する必要があるとします。コードは次のようになります-
まず、検索時に有効な結果を取得できるように、顧客名を「ABC」としてInvoiceオブジェクトに単一のレコードを作成する必要があります。
// 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について説明します。
これは、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つの関連オブジェクトレコードを挿入する必要がある場合もあります。たとえば、InvoiceオブジェクトはCustomerオブジェクトと関係があるため、1人のCustomerが多数の請求書を持つことができます。
請求書を作成していて、この請求書を顧客に関連付ける必要があるとします。この機能には次のコードを使用できます-
// 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で同じものを開きます。以下に示すように、親レコードがすでに請求書レコードに割り当てられていることがわかります。
子レコードの取得
ここで、特定の顧客レコードに関連するすべての請求書を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_Customer__r.Nameという表記を使用しました。APEX_Customer__rは親関係の名前です。ここでは、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 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クラスには、2つのキーワードで制御できるセキュリティ設定があります。
データセキュリティと共有ルール
Apexは通常、システムコンテキスト、つまり現在のユーザーのアクセス許可で実行されます。コードの実行時には、フィールドレベルのセキュリティと共有ルールは考慮されません。匿名ブロックコードのみが、コードを実行しているユーザーの許可を得て実行されます。
私たちのApexコードは、セキュリティと共有設定によって隠されている機密データをユーザーに公開してはなりません。したがって、Apexのセキュリティと共有ルールの適用が最も重要です。
共有キーワード付き
このキーワードを使用すると、Apexコードは、現在のユーザーの共有設定をApexコードに強制します。これはプロファイル権限を強制せず、データレベル共有設定のみを強制します。
ユーザーが5つのレコードにアクセスできるが、レコードの総数が10である例を考えてみましょう。したがって、Apexクラスが「WithSharing」キーワードで宣言されると、ユーザーが返す5つのレコードのみが返されます。にアクセスできます。
Example
まず、Customerオブジェクトに少なくとも10レコードを作成し、5レコードの「Name」を「ABCCustomer」として、残りの5レコードを「XYZCustomer」として作成したことを確認します。次に、「ABC顧客」をすべてのユーザーと共有する共有ルールを作成します。また、CustomerオブジェクトのOWDがPrivateとして設定されていることを確認する必要があります。
以下のコードを開発者コンソールの匿名ブロックに貼り付けます。
// 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クラスセキュリティの設定
Step 1 −「セットアップ」から、「開発」→「Apexクラス」をクリックします。
Step 2−制限するクラスの名前をクリックします。CustomerOperationClassをクリックしました。
Step 3 − [セキュリティ]をクリックします。
Step 4 − [使用可能なプロファイル]リストから有効にするプロファイルを選択して[追加]をクリックするか、[有効なプロファイル]リストから無効にするプロファイルを選択して[削除]をクリックします。
Step 5 − [保存]をクリックします。
権限セットからのApexセキュリティの設定
Step 1 − [設定]から、[ユーザーの管理]→[権限セット]をクリックします。
Step 2 −権限セットを選択します。
Step 3 − Apex ClassAccessをクリックします。
Step 4 − [編集]をクリックします。
Step 5 − [使用可能なApexクラス]リストから有効にするApexクラスを選択して[追加]をクリックするか、[有効なApexクラス]リストから無効にするApexクラスを選択して[削除]をクリックします。
Step 6 − [保存]ボタンをクリックします。
Apexの呼び出しとは、Apexクラスを実行するプロセスを指します。Apexクラスは、以下のいずれかの方法で呼び出された場合にのみ実行できます。
トリガーと匿名ブロック
指定されたイベントに対して呼び出されるトリガー
非同期の頂点
指定された間隔で実行するようにApexクラスをスケジュールするか、バッチジョブを実行します
Webサービスクラス
Apexメールサービスクラス
Apex Webサービス。これにより、SOAPおよびRESTWebサービスを介してメソッドを公開できます。
Visualforceコントローラー
インバウンドEメールを処理するApexEメールサービス
JavaScriptを使用したApexの呼び出し
Apexに実装されたWebサービスメソッドを呼び出すためのAjaxツールキット
これで、Apexを呼び出す一般的な方法をいくつか理解できます。
匿名ブロックの実行から
以下に示すように、開発者コンソールで匿名実行を介してApexクラスを呼び出すことができます-
Step 1 −開発者コンソールを開きます。
Step 2 − [デバッグ]をクリックします。
Step 3−以下のように匿名実行ウィンドウが開きます。次に、[実行]ボタンをクリックします-
Step 4 − [ログ]ペインに表示されたら、デバッグログを開きます。
トリガーから
Triggerから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 Page Code
Apex Class Code (Controller Extension)
Apexトリガーは、特定のイベントが発生したときに実行されるストアドプロシージャのようなものです。トリガーは、レコードでイベントが発生する前後に実行されます。
構文
trigger triggerName on ObjectName (trigger_events) { Trigger_code_block }
トリガーの実行
以下は、トリガーを発生させることができるイベントです-
- insert
- update
- delete
- merge
- upsert
- undelete
トリガーの例1
顧客の「顧客ステータス」フィールドが非アクティブからアクティブに変わったときに請求書レコードを作成する必要があるというビジネス要件を受け取ったとします。このために、次の手順に従ってAPEX_Customer__cオブジェクトにトリガーを作成します-
Step 1 −sObjectに移動します
Step 2 −顧客をクリックします
Step 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
上記のトリガーは、顧客レコードに更新操作がある場合に実行されます。請求書レコードを挿入する必要があるのは、顧客ステータスが非アクティブからアクティブに変わるときだけであり、毎回ではないとします。このために、別のコンテキスト変数を使用できますtrigger.oldMap キーをレコードIDとして保存し、値を古いレコード値として保存します。
// 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と古い値を格納するコンテキスト変数です。
デザインパターンは、コードをより効率的にし、ガバナーの制限に達しないようにするために使用されます。多くの場合、開発者は、オブジェクトのインスタンス化を繰り返す可能性のある非効率的なコードを作成できます。これにより、コードの効率が低下し、パフォーマンスが低下し、ガバナーの制限に違反する可能性があります。これは、一連のレコードに対して動作できるため、トリガーで最も一般的に発生します。
この章では、いくつかの重要なデザインパターン戦略について説明します。
バルクトリガーデザインパターン
実際のビジネスケースでは、一度に数千のレコードを処理する必要がある場合があります。トリガーがそのような状況を処理するように設計されていない場合、レコードの処理中に失敗する可能性があります。トリガーを実装する際に従う必要のあるベストプラクティスがいくつかあります。すべてのトリガーはデフォルトで一括トリガーであり、一度に複数のレコードを処理できます。一度に複数のレコードを処理することを常に計画する必要があります。
多数のレコードを処理する必要があり、以下に示すようにトリガーを記述したビジネスケースについて考えてみます。これは、顧客ステータスが非アクティブからアクティブに変わったときに請求書レコードを挿入するために行ったのと同じ例です。
// 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クラスを呼び出し、処理をTriggerからApexクラスに委任する必要があります。Trigger Helperクラスは、トリガーのすべての処理を行うクラスです。
請求書レコードの作成例をもう一度考えてみましょう。
// 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
}
}
ガバナーの実行制限により、Force.comマルチテナントプラットフォーム上のリソースを効率的に使用できます。これは、効率的な処理のためにコード実行に関してSalesforce.comによって指定された制限です。
知事の制限とは何ですか?
ご存知のとおり、Apexはマルチテナント環境で実行されます。つまり、単一のリソースがすべての顧客と組織によって共有されます。したがって、誰もリソースを独占しないようにする必要があります。そのため、Salesforce.comは、コードの実行を管理および制限する一連の制限を作成しました。ガバナーの制限のいずれかを超えると、エラーがスローされ、プログラムの実行が停止します。
開発者の観点からは、コードがスケーラブルであり、制限に達しないようにすることが重要です。
これらの制限はすべて、トランザクションごとに適用されます。単一のトリガーの実行は1つのトランザクションです。
これまで見てきたように、トリガーの設計パターンは制限エラーを回避するのに役立ちます。ここで、他の重要な制限が表示されます。
SOQLクエリ制限の回避
トランザクションごとに発行できるクエリは100のみです。つまり、コードが100を超えるSOQLクエリを発行すると、エラーがスローされます。
例
この例は、SOQLクエリの制限に到達する方法を示しています-
次のトリガーは、顧客のリストを反復処理し、子レコードの(請求書)説明を文字列「OktoPay」で更新します。
// 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と顧客レコードのマップを取得します。
// 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バルクコール
この例は、バルクトリガーとトリガーヘルパークラスパターンを示しています。最初にヘルパークラスを保存してから、トリガーを保存する必要があります。
Note −以前に作成した「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
}
その他のSalesforceGovernorの制限
次の表に、ガバナーの重要な制限を示します。
説明 | 制限 |
---|---|
合計ヒープサイズ | 6 MB / 12 MB |
発行されたDMLステートメントの総数 | 150 |
1回のSOSLクエリで取得されたレコードの総数 | 2000年 |
発行されたSOSLクエリの総数 | 20 |
Database.getQueryLocatorによって取得されたレコードの総数 | 10000 |
SOQLクエリによって取得されたレコードの総数 | 50000 |
この章では、Apexでのバッチ処理について説明します。毎日多数のレコードを処理するシナリオを考えてみましょう。おそらくデータのクリーニングや、未使用のデータの削除などです。
Batch Apexとは何ですか?
Batch Apexは、Apexコードの非同期実行であり、多数のレコードを処理するために特別に設計されており、同期コードよりもガバナ制限の柔軟性が高くなっています。
いつBatchApexを使用しますか?
毎日、または特定の間隔で多数のレコードを処理する場合は、BatchApexを使用できます。
また、操作を非同期にしたい場合は、BatchApexを実装できます。Batch Apexは、開発者が実装する必要のあるインターフェイスとして公開されています。バッチジョブは、Apexを使用して実行時にプログラムで呼び出すことができます。Batch Apexは、レコードの小さなバッチで動作し、レコードセット全体をカバーし、処理を管理可能なデータのチャンクに分割します。
BatchApexの使用
Batch Apexを使用する場合は、Salesforceが提供するインタフェースDatabase.Batchableを実装してから、プログラムでクラスを呼び出す必要があります。
次の手順に従ってクラスを監視できます-
バッチApexバッチジョブの実行を監視または停止するには、[設定]→[監視]→[Apexジョブ]または[ジョブ]→[Apexジョブ]に移動します。
Database.Batchableインターフェースには、実装する必要のある次の3つのメソッドがあります-
- Start
- Execute
- Finish
それぞれの方法を詳しく理解しましょう。
開始
Startメソッドは、Database.Batchableインターフェイスの3つのメソッドの1つです。
Syntax
global void execute(Database.BatchableContext BC, list<sobject<) {}
このメソッドは、バッチジョブの開始時に呼び出され、バッチジョブが動作するデータを収集します。
方法を理解するために以下の点を考慮してください-
使用 Database.QueryLocator単純なクエリを使用してバッチジョブで使用されるオブジェクトのスコープを生成する場合のオブジェクト。この場合、SOQLデータ行の制限はバイパスされます。
レコードを処理するための複雑な基準がある場合は、反復可能オブジェクトを使用します。Database.QueryLocatorは、処理する必要のあるレコードのスコープを決定します。
実行する
ここで、Database.BatchableインターフェイスのExecuteメソッドについて理解しましょう。
Syntax
global void execute(Database.BatchableContext BC, list<sobject<) {}
ここで、list <sObject <はDatabase.QueryLocatorメソッドによって返されます。
このメソッドはStartメソッドの後に呼び出され、バッチジョブに必要なすべての処理を実行します。
終了
次に、Database.BatchableインターフェイスのFinishメソッドについて説明します。
Syntax
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メソッドがバッチジョブを実行します。ジョブが完了すると、指定された電子メールアドレスに電子メールが送信されます。あなたが持っている顧客記録を持っていることを確認してくださいActive チェックされたように。
// Paste in Developer Console
CustomerProessingBatch objClass = new CustomerProessingBatch();
Database.executeBatch (objClass);
このクラスが実行されたら、情報が記載された電子メールを受信する場所に指定した電子メールアドレスを確認します。また、上記の[監視]ページと手順を使用して、バッチジョブのステータスを確認できます。
デバッグログを確認すると、処理されたレコードの数を示すリストサイズを見つけることができます。
Limitations
一度に実行できるバッチジョブ処理は5つだけです。これは、BatchApexの制限の1つです。
Apex詳細ページを使用したApexバッチジョブのスケジュール
以下に示すように、Apexの詳細ページからApexクラスをスケジュールできます。
Step 1 − [設定]⇒[Apexクラス]に移動し、[Apexクラス]をクリックします。
Step 2 − [頂点のスケジュール]ボタンをクリックします。
Step 3 −詳細を提供します。
スケジュール可能なインターフェイスを使用した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には、デバッグに使用できる特定のツールがあります。それらの1つは、デバッグログに変数の値と出力を出力するsystem.debug()メソッドです。
デバッグには次の2つのツールを使用できます-
- 開発者コンソール
- デバッグログ
開発者コンソールを介したデバッグ
以下のように、開発者コンソールを使用して、Apexをデバッグするための匿名機能を実行できます。
Example
今日作成された顧客レコードをフェッチする既存の例を考えてみましょう。クエリが結果を返しているかどうかを知りたいだけです。返されている場合は、Listの値を確認します。
以下のコードを実行匿名ウィンドウに貼り付け、実行匿名ウィンドウを開くために行った手順に従います。
Step 1 −開発者コンソールを開きます
Step 2 −以下に示すように、「デバッグ」から匿名実行を開きます。
Step 3 − [匿名の実行]ウィンドウを開き、次のコードを貼り付けて、[実行]をクリックします。
// 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
Step 4 −以下に示すようにログを開きます。
Step 5 −以下に示すように、フィルター条件に「USER」と入力します。
Step 6 −以下に示すように、USERDEBUGステートメントを開きます。
デバッグログを介したデバッグ
デバッグログを介して同じクラスをデバッグすることもできます。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);
}
}
}
以下の手順に従って、デバッグログを生成します。
Step 1−ユーザーのデバッグログを設定します。[設定]に移動し、検索設定ウィンドウに「デバッグログ」と入力して、[リンク]をクリックします。
Step 2 −デバッグログを次のように設定します。
Step 3−設定が必要なユーザー名を入力します。ここにあなたの名前を入力してください。
Step 4 −デバッグログを生成するためにイベントが発生する必要があるため、顧客レコードを変更します。
Step 5−ここで、デバッグログセクションに再度移動します。デバッグログを開き、[リセット]をクリックします。
Step 6 −最初のデバッグログの表示リンクをクリックします。
Step 7 −以下に示すように、ブラウザ検索を使用して文字列「USER」を検索します。
デバッグステートメントには、ポイントを設定したフィールドの値が表示されます。
テストは、Apexまたはその他のアプリケーション開発の統合された部分です。Apexには、すべての単体テスト用に開発する個別のテストクラスがあります。
テストクラス
SFDCでは、本番環境にデプロイするには、コードのコードカバレッジが75%である必要があります。このコードカバレッジは、テストクラスによって実行されます。テストクラスは、他のApexクラスの機能をテストするコードスニペットです。
以前に作成したコードの1つに対してテストクラスを作成しましょう。TriggerおよびHelperクラスコードをカバーするテストクラスを作成します。以下は、カバーする必要のあるトリガーとヘルパークラスです。
// 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を追加しました。
Example
/**
* 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
}
}
テストクラスの実行
以下の手順に従って、テストクラスを実行します-
Step 1 −Apexクラスに移動⇒クラス名「CustomerTriggerTestClass」をクリックします。
Step 2 −図のように[テストの実行]ボタンをクリックします。
Step 3 −ステータスを確認する
Step 4 −ここで、テストを作成したクラスとトリガーを確認します
クラス
引き金
テストは成功し、完了しました。
SFDCでの展開とは何ですか?
これまでDeveloperEditionでコードを開発しましたが、実際のシナリオでは、サンドボックスでこの開発を行う必要があります。その後、これを別のサンドボックスまたは本番環境にデプロイする必要があります。これをデプロイメントと呼びます。要するに、これはある組織から別の組織へのメタデータの移動です。この背後にある理由は、Salesforce本番組織でApexを開発できないためです。開発中にシステムにアクセスするライブユーザーは、データを不安定にしたり、アプリケーションを破損したりする可能性があります。
展開に利用できるツール-
- Force.com IDE
- セットの変更
- SOAP API
- Force.com移行ツール
開発と学習の目的でDeveloperEditionを使用しているため、SFDCエンタープライズまたはその他の有料版を必要とする変更セットやその他のツールを使用することはできません。したがって、このチュートリアルでは、Force.comIDEの展開方法について詳しく説明します。
Force.com Eclipse IDE
Step 1 − Eclipseを開き、デプロイする必要のあるクラストリガーを開きます。
Step 2 − [サーバーに展開]をクリックしたら、コンポーネントを展開する必要がある組織のユーザー名とパスワードを入力します。
上記の手順を実行することにより、Apexコンポーネントがターゲット組織に展開されます。
変更セットを使用した展開
検証ルール、ワークフロールール、Apexクラス、およびトリガーを、展開設定を介して接続することにより、ある組織から別の組織に展開できます。この場合、組織は接続されている必要があります。
展開セットアップを開くには、以下の手順に従います。この機能はDeveloperEditionでは使用できないことに注意してください-
Step 1 −セットアップに移動し、「展開」を検索します。
Step 2 −デプロイする変更セットを作成するには、「アウトバウンド変更セット」をクリックします。
Step 3 − [追加]ボタンを使用して変更セットにコンポーネントを追加し、[保存]をクリックして[アップロード]をクリックします。
Step 4 −ターゲット組織に移動し、インバウンド変更セットをクリックして、最後にデプロイをクリックします。
デプロイするSOAPAPI呼び出し
これは一般的に使用される方法ではないため、この方法の概要を簡単に説明します。
以下に示すメソッド呼び出しを使用して、メタデータをデプロイできます。
- compileAndTest()
- compileClasses()
- compileTriggers()
Force.com移行ツール
このツールは、スクリプトによる展開に使用されます。Force.com移行ツールをダウンロードする必要があります。そうすれば、ファイルベースの展開を実行できます。Force.com移行ツールをダウンロードして、スクリプトによる展開を行うことができます。