Apex入門

salesforce

TRAILHEAD

本記事は以下のTRAILHEADの内容をまとめたもののため以下を実施が前提となる

/* 取得もとの変数によってリストか単体かが自動で判定される */
// リスト
List<SObject> objList = [SELECT colomn FROM SObject];
// 単体
SObject obj = [SELECT colomn FROM SObject];

またWHERE句などSQLと同じように条件を指定することができる

/* nameの値が取引先Aになっている取引先オブジェクトを取得 */
// リスト
List<Account> actList = [SELECT name FROM account WHERE name = `取引先A`];
// 単体
Account act = [SELECT name FROM account WHERE name = `取引先A`];

DML

DMLとは

Salesforce上の各オブジェクト(テーブル)を登録/更新/削除するための処理のこと。

insert

新規レコード登録

List<Account> actList = new List<Account>();
actList.add(act);
/**
 * Database.insert
 * @param 登録対象(リストまたは単体)
 * @param エラー時のロールバック範囲。ture: すべて false: 単体
 */
Database.insert(actList, false);

update

レコード更新

List<Account> actList = [SELECT id, name FROM account WHERE name = `取引先A`];
/**
 * Database.update
 * @param 更新対象(リストまたは単体)
 * @param エラー時のロールバック範囲。ture: すべて false: 単体
 */
Database.update(actList, false);

upsert

  • レコードの作成/更新
List<Account> actList = [SELECT id, name FROM account WHERE name = `取引先A`];
Account act = new Account(Name= '取引先A');
actList.add(act);
/**
 * Database.upsert
 * @param 保存対象(リストまたは単体)
 * @param キー この値が一致するレコードを更新。一致しないレコードは新規作成
 * @param エラー時のロールバック範囲。ture: すべて false: 単体
 */
Database.upsert(actList, Account.Fields.name, false);

delete

レコード削除

List<Account> actList = [SELECT id FROM account WHERE name = `取引先A`];
/**
 * Database.delete
 * @param delete(リストまたは単体) idが一致するデータを削除
 * @param エラー時のロールバック範囲。ture: すべて false: 単体
 */
Database.delete(actList, false);

※ よく調べるやつ

構文的にSQLと同じ箇所が多いが大きく違う箇所が以下の2点になる

  1. 取得する項目はSELECTするときに必ず記載しなければならない。上記のようにnameだけ記載した場合は作成日などは取得できない。ただしIDだけはデフォルトで取得できる。「*」は使用できない

外部サイト: Salesforce Spring ’21の新機能、SOQLのFIELDS()関数について

  1. ガバナ制限に注意しなければならない。具体的には一回の重い処理する場合などに制限がある。

非同期処理

非同期処理とは

通常Apexのプログラムは一つのスレッド上で実行される。非同期処理では複数のスレッドで処理が実行される。
ガバナ制限の回避や、大量のデータをやり取りする場合はバッチ処理を使用する。

@future

アノテーションを使う ※使用頻度は高くないためコード例のみ記載

@future
public void メソッド名() {
    // 非同期処理
}

Apex 開発者ガイド: future のメソッド

Database.Batchable

バッチ(Database.Batchable)を使う

  • Database.QueryLocatorまたはIterableを使用できるが、基本的には前者を使用していればよい。より複雑な処理を行う場合のみ後者を選択する。そのため本記事には前者のみの説明とする。
  • Database.Batchable インターフェースには、実装が必要な次の 3 つのメソッドが含まれています。
// 1. startメソッド
public Database.QueryLocator start(Database.BatchableContext bc) {}
// 2. executeメソッド
public void execute(Database.BatchableContext BC, list<P>){}
// 3. finishメソッド
public void finish(Database.BatchableContext BC){}
  • バッチを実行するには以下のメソッドを実行する
/**
 * Database.executeBatch バッチの実行
 * @param バッチのインスタンス
 * @param バッチのサイズ 一回の非同期処理に対しての処理件数。指定しない場合デフォルト200。最大2000。
 */
Database.executeBatch(new Batch(), 200);

ポイント : バッチの全体的な動きとしては以下のような動きになる

1.start -> 2.execute x (取得データサイズ/バッチサイズ) -> 5.finish

- 1つ目のstartで検索結果がバッチサイズごとにexecuteが実行される
- executeで処理できるものがなくなり次第finishが呼ばれバッチが終了する
image

Apex 開発者ガイド: Apex の一括処理の使用

スケジューラ

スケジューラとは

非同期処理の一つ。Salesforce上で設定した曜日に間隔的に実行することができる。

スケジューラの使用例

以下のクラスを作成するだけでSalesforce上で以下クラスのスケジュール設定を行うことができる

global class SampleClass implements Schedulable {
    global void execute(SchedulableContext ctx) {
        // 処理
    }
}

トリガ

トリガとは

オブジェクトが登録や更新などのアクションを起こした際に呼ばれるもの。アクション前、後などタイミングを選択することができる。

トリガの使用例

以下の引数をトリガに渡すことによってイベントを取得することができる

  • before insert 登録前処理
  • before update 登録前処理
  • before delete 削除前処理
  • after insert 登録後処理
  • after update 更新後処理
  • after delete 削除後処理
  • after undelete ごみ箱からの復元後処理
    // Account登録更新前に呼ばれる
    trigger HelloWorldTrigger on Account (before insert, before update) {
    // 処理
    }

Apex 開発者ガイド: Trigger クラス

ガバナ制限

ガバナ制限とは

Salesforceでは一つのリソースを複数の会社が共有しているためメモリやCPU、DBなどを大きく占有する処理の制限のこと。
ここは最重要だがSQOLを使用する際に毎回調べれば覚えられる範囲なので、暗記しなくても良い
クイックリファレンス: Apex ガバナ制限

Apexテスト

Apexテストとは

Apexテストは単体テストとも呼ばれる。テストコードは基本的に自分がコーディングした箇所が正常に動いているかを確認するもの。
コーディングした範囲が最低でも75%以上通るようにするが、基本的には100%通るようにする。

具体的なテストパターン

必須ではないカスタム項目「colomnA__c(テキスト)」「colomnB__c(チェックボックス)」をAccountオブジェクトに作成する。

public class SampleClass {
    public void execute() {
        Account act = [SELECT colomnA__c, colomnB__c FROM Account Limit 1];
        act.colomnB__c = act.colomnA__c == 'Active' ? false : true;
        Database.update(act, false);
    }
}

上記のSampleClassでは適当に取得したAccountnoレコードのcolomnA__cの値が’Active’の場合はcolomnB__cの値にfalse、それ以外の場合trueが入る処理になっている。
このクラスをテストするには以下のパターンが想定される

項目名パターン1パターン2
条件colomnA__cの値ActiveDeleted(Active以外)
結果colomnA__cの値falsetrue

コーディングした場合以下になる。
クラス名とテストメソッド名に@isTestを記載する

@isTest
public class SampleTestClass {
    /**
     * 条件: colomnA__cの値がActive
     * 期待値: colomnB__cの値がfalse
     */
    @isTest
    public static void executeClmAIsActiveTest() {
        // テスト用のデータを作成
        Account newAccount = new Account(colomnA__c = 'Active');
        insert newAccount;
        // テスト実施
        SampleClass newSampleClass = new SampleClass();
        newSampleClass.execute();
        // 確認
        Account act = [SELECT colomnB__c FROM Account Limit 1];
        // 第一引数と第二引数の値が一致していない場合テストでエラーが起こる
        System.assertEquals(act.colomnB__c, false);
    }
    /**
     * 条件: colomnA__cの値がActive以外
     * 期待値: colomnB__cの値がtrue
     */
    @isTest
    public static void executeClmAIsDeletedTest() {
        // テスト用のデータを作成
        Account newAccount = new Account(colomnA__c = 'Deleted');
        insert newAccount;
        // テスト実施
        SampleClass newSampleClass = new SampleClass();
        newSampleClass.execute();
        // 確認
        Account act = [SELECT colomnB__c FROM Account Limit 1];
        // 第一引数と第二引数の値が一致していない場合テストでエラーが起こる
        System.assertEquals(act.colomnB__c, true);
    }
}