【Salesforce】Apexで書くTriggerとは?|実例付

※本サイトにはプロモーション・広告が含まれています。

(最終更新月: 2023年12月)

✔以下の疑問をお持ちの方へ向けた記事です

「SalesforceのApexトリガーとは何か?」
「Apexトリガーの作成と使用法を理解したい」
「Apexトリガーを使った実践的な例を知りたい」

✔当記事を読むことで得られる知識

  • SalesforceにおけるApexトリガーの基本概念
  • Apexトリガーの作成方法と主な機能
  • Apexトリガーを使用した具体的な実装例

当記事では、SalesforceにおけるApexトリガーの重要性と基本的な概念を紹介します。

トリガーの作成方法やさまざまなタイプのトリガー(beforeトリガー、afterトリガーなど)、およびこれらを使用した具体的なプログラミング例について詳しく解説します。

Salesforceの開発者や学習者にとって、実践的なガイドとなる内容です。

ぜひ最後までご覧ください。

Salesforce

定義や属性などは公式ガイドを必ず参考にしましょう。

当記事では、主にその使い方を具体例とともに解説します。

筆者プロフィール

筆者プロフィールアイコン

【現職】プロダクトマネージャー

プロダクトマネージャーとして、Apex・Visualforceの開発エンジニアとして、以下のようなプロジェクトに従事してきました

  • 新規事業の立ち上げに伴うビジネスプロセス構築とSalesforceのカスタマイズ
  • SFDXを活用した大規模リリース
  • Visualforce等による一般ユーザー向けサイト・アプリケーションの構築

相談・業務の依頼も承ります。ご質問・ご希望をお問い合わせください。

Apexトリガーの基本

Apexトリガーの基本に関する情報をお届けします。

ApexトリガーはSalesforce開発において欠かせない要素で、Salesforce内でのデータ管理やビジネスプロセスの自動化を理解し、活用できるようになります。

  • Apexトリガーとは何か
  • トリガーの役割とSalesforce内での重要性
  • トリガーの種類: BeforeとAfter
  • トリガー内でのレコード取得方法

Apexトリガーとは何か

ApexトリガーはSalesforce上で特定のオブジェクトのレコードに変更が発生した際に自動的に実行されるカスタムコードです。

具体的に変更とは、レコードに以下がおこなわれたときになります。

  • レコードが挿入(INSERT)
  • 更新(UPDATE)
  • 削除(DELETE)
  • 復元(UNDELETE)

以下はApexトリガーを定義するための基本的なコード構造です。

trigger MyTrigger on Account (before insert, before update) {
    // ここにトリガーで実行したい処理を記述
}

記述したトリガーは、アカウントオブジェクトに新しいレコードが挿入される前や、既存のレコードが更新される前に実行されます。

こうしたトリガーはビジネスロジックを効率的に実装するために不可欠です。

トリガーの役割とSalesforce内での重要性

トリガーは、Salesforceレコードに変更がおこなわれたとき、自動化されたチェックやデータ処理を実行するもの。

例えば、顧客データとアカウントデータ間の整合性を保証するために、トリガーが自動的に関連データを更新することがあります。

これはデータの品質とビジネスプロセスの効率性を維持する上で非常に重要です。

トリガーの種類: BeforeとAfter

トリガーはその実行タイミングにより、「Before」トリガーと「After」トリガーに大別されます。

  • Beforeトリガー: データベースに保存される前に実行され、データの検証や値の変更に用いる
  • Afterトリガー: データベースへの保存後に実行され、関連するレコードを操作する際や、非同期の処理などを実行する際に利用される

例えば、次のように定義されます。

trigger AccountAfterTrigger on Account (after insert, after update) {
    // データベースにレコードが保存された後の処理
}

このトリガーは、アカウントレコードがデータベースに挿入または更新された後に実行される処理を指定します。

トリガー内でのレコード取得方法

トリガー内でレコードを取得する方法として、以下を覚えておきましょう。

  • forループを使う
  • Trigger.new

具体的には以下のようなコードになります。

trigger AccountAfterTrigger on Account (after insert, after update) {
    // データベースにレコードが保存された後の処理
    for (Account acc: Trigger.new){
        //保存後の取引先レコードはaccとなります。
    // 一括保存した場合は、複数のレコードが、Trigger.newで取得できます。
    }
}

Apexトリガーの開発

こちらでは、初心者がトリガーの開発に着手する際に知っておくべき基本手順やデータ検証・処理の自動化方法を説明します。

Salesforceのカスタム開発環境において、Apexトリガーの開発は欠かせない要素です。

  • トリガーの作成手順
  • トリガー内の基本的なコーディングパターン
  • データ検証と処理の自動化

トリガーの作成手順

Apexトリガーを作成する際の手順は以下のとおりです。

  • Salesforceの開発者コンソールを開く
  • 新しいトリガーをファイルメニューから作成
  • トリガーを管理するオブジェクトと名前を入力

以上に基づいてApexコードを記述します。

trigger testTrigger on Account (before insert) {
    // 新規レコードが挿入される前に行いたい処理を記述する
}

コードを記述したら、保存してコンパイルを行い、エラーがないことを確認します。

トリガー内の基本的なコーディングパターン

トリガーを記述する際には一般的なコーディングパターンがあります。

そのひとつが、トリガーが発火した際に処理対象となるレコードをループで回して処理をおこなうというものです。

例えば、以下のように新しく挿入される各レコードに対して特定の値を設定できます。

trigger SetDefaultRegion on Contact (before insert) {
    for (Contact c : Trigger.new) {
        c.Region__c = '未指定'; // デフォルトの地域を設定
    }
}

このコードは新しく挿入される各連絡先レコードに対して、Region__cというカスタムフィールドにデフォルト値として「未指定」を設定する処理をおこないます。

データ検証と処理の自動化

トリガーは、データ検証と処理を実行するための自動化ツールとしても機能します。

例えば、以下のトリガーは連絡先レコードが作成または更新される際に、電子メールアドレスの形式が適切かどうかをチェックし、不適切であればエラーを発生させる処理をおこないます。

trigger ValidateEmail on Contact (before insert, before update) {
    for (Contact c : Trigger.new) {
        if (!Pattern.matches('\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*', c.Email)) {
            c.addError('無効なメールアドレスです。');
        }
    }
}

このトリガーは、正規表現を用いてメールアドレスのフォーマットを検証し、問題があればエラーメッセージを表示します。

これにより、データ入力時の誤りを自動的に防げます。

Apexトリガーの実践的応用

Apexトリガーはその応用範囲が広く、多様な実践的なシナリオで活用できます。

データ整合性の維持、複雑なビジネスルールの実装、システムイベントとの連動など、具体的な使用事例について見ていきましょう。

  • データ整合性の維持
  • 複雑なビジネスルールの実装
  • システムイベントと連動した処理

データ整合性の維持

データ整合性を維持するために、Apexトリガーはデータの重複チェックや関連データの同期などに利用されます。

たとえば新しい取引先がシステムに追加された際、自動的に関連する連絡先レコードを検索し、取引先レコードに対応するフィールドを更新するトリガーを考えてみましょう。

trigger SyncAccountContacts on Account (after insert) {
    for (Account acc : Trigger.new) {
        Contact[] relatedContacts = [SELECT Id, AccountId FROM Contact WHERE AccountId = :acc.Id];
        for (Contact c : relatedContacts) {
            c.AccountRegion__c = acc.Region__c; // 同期するフィールド
            update c;
        }
    }
}

このトリガーはAccountレコードが追加された後、関連するContactレコードを検索し、取引先の地域情報で連絡先レコードを更新します。

複雑なビジネスルールの実装

Apexトリガーは、特定のビジネスルールに基づいて複雑な条件分岐やデータの処理を実行するのに適しています。

例として、受注金額に応じて顧客に割引率を設定するトリガーを見ていきましょう。

trigger ApplyDiscount on Opportunity (before update) {
    for (Opportunity opp : Trigger.new) {
        if (opp.Amount >= 100000) {
            opp.Discount__c = 0.1; // 10%割引
        } else if (opp.Amount >= 50000) {
            opp.Discount__c = 0.05; // 5%割引
        } else {
            opp.Discount__c = 0; // 割引なし
        }
    }
}

このトリガーは商談レコードを更新する際に、金額に応じて自動的に割引率を計算し、適用するために実行されます。

システムイベントと連動した処理

システム内のイベントに応じて、ほかのオブジェクトへの通知など、さまざまな処理を自動化できます。

例えば、顧客サービスのケースが解決された瞬間に担当者に自動で通知するトリガーを設定してみましょう。

trigger NotifyOnCaseResolution on Case (after update) {
    for (Case cs : Trigger.new) {
        if (cs.Status == 'Resolved') {
            // 通知ロジックをここに実装する
            // EmailManager.sendNotification(cs.AssignedTo, 'Case Resolved', 'Case ' + cs.CaseNumber + ' has been resolved.');
        }
    }
}

このトリガーはケースの状態が解決に変更された後、担当者に解決通知を送るコードを実行します。

Apexトリガーのベストプラクティス

Apexトリガーを正しく効率的に実装するためのベストプラクティスが存在します。

これらを適用することで、メンテナンスが容易で、拡張性が高く、パフォーマンスに優れたコードを書けます。

  • トリガーのモジュール化と再利用
  • パフォーマンスと制限の管理
  • トリガーのテストとデプロイメント

トリガーのモジュール化と再利用

トリガーをモジュール化することで、共通の機能をもつコードを再利用し、トリガーの保守性を高められます。

単一のトリガーに複数の処理を書き込むのではなく、ヘルパークラスやサービスクラスにロジックを分割して管理することで、よりクリーンなコード管理が可能です。

例えば、以下のような形です。

public class AccountTriggerHandler {
    public static void handleBeforeInsert(List<Account> newAccounts) {
        // 挿入前に行う特定の処理
    }
}

trigger AccountTrigger on Account (before insert) {
    AccountTriggerHandler.handleBeforeInsert(Trigger.new);
}

Accountレコードが挿入される前に実行されるトリガーであり、処理内容はAccountTriggerHandlerクラスのhandleBeforeInsertメソッドに委ねられています。

これにより、トリガーロジックが分散され、再利用性が向上するのです。

パフォーマンスと制限の管理

トリガーで大量のデータを扱う際は、Salesforceのガバナ制限を超えないよう、トリガーの設計が必要です。

トリガー内のDML操作やSOQLクエリの回数を最小限に抑え、エラーを防ぎましょう。

例えば、ループの中でDML文を実行するのではなく、コレクションを利用したバルク操作により、制限を守る方法などです。

trigger ContactTrigger on Contact (after insert) {
    List<Task> tasksToCreate = new List<Task>();
    for (Contact con : Trigger.new) {
        if (con.FollowUpNeeded__c) {
            tasksToCreate.add(new Task(Subject = 'Follow-Up', WhoId = con.Id));
        }
    }
  //forループの外で実施
    if (tasksToCreate.size() > 0) {
        insert tasksToCreate; // バルクDML操作
    }
}

このトリガーでは、連絡先が挿入された後、追跡が必要な場合にタスクを作成することを示しており、バルクDML操作を使用してガバナ制限の範囲内で処理を行っています。

ガバナ制限についてはこちらの記事をご覧ください。

トリガーのテストとデプロイメント

Apexトリガーを本番環境にデプロイする前には、十分なテストを実施することが非常に重要です。

Apexクラスとテストクラスを用いて、トリガーの動作が正しいかを保証します。

またとくにエッジケースや例外ケースを含めた網羅的なテストが必要です。

以下はテストクラスのサンプルになります。

@isTest
private class ContactTriggerTest {
    @isTest static void testContactInsertion() {
        List<Contact> contactsToTest = new List<Contact>{
            new Contact(FirstName = 'Test', LastName = 'Contact1', Email = 'test1@example.com'),
            new Contact(FirstName = 'Test', LastName = 'Contact2', Email = 'test2@example.com')
        };

        Test.startTest();
        insert contactsToTest;
        Test.stopTest();

        // 以下でトリガーによる副作用をアサートする
    }
}

このテストクラスは、連絡先レコードの挿入をシミュレートし、トリガーが期待通りに動作することを確認しています。

トリガーの実行結果を検証するコードが含まれています。

Apexトリガーのトラブルシューティング

Apexトリガーの開発では、様々なエラーや問題に直面することがあります。

一般的なエラーの特定と解決、デバッグとパフォーマンスチューニング、そしてバージョン管理と変更履歴の追跡について見ていきましょう。

  • 一般的なエラーとその解決策
  • デバッグとパフォーマンスチューニング
  • バージョン管理と変更履歴

一般的なエラーとその解決策

Apexトリガーの開発においては、コンパイルエラーやランタイムエラー、ガバナ制限の違反など多様なエラーに遭遇する可能性があります。

例えば、トリガーが実行される際、以下のようなエラーメッセージが表示されることがあります。

System.QueryException: List has no rows for assignment to SObject

このエラーは、SOQLクエリの結果が何も返さない場合に発生するもので、エラーハンドリングで適切な処理を施すべきです。

以下のように修正することで、エラーへの対応が可能です。

Account acc = [SELECT Id, Name FROM Account WHERE Name = 'Acme' LIMIT 1];
if (acc != null) {
    // アカウントに関する処理
} else {
    // アカウントが取得できなかった場合の処理
}

デバッグとパフォーマンスチューニング

開発中のトリガーや既存のトリガーのデバッグは、問題の特定と修正に不可欠です。

また、パフォーマンスの低下を引き起こすコードを見つけるためにも重要なステップ。

デバッグログを利用して実際にコードが実行される様子を追い、問題のある箇所を特定しましょう。

ログの表示にはSystem.debugを使用します。

trigger DebugExample on Account (after insert) {
    System.debug('Trigger executed with following records: ' + Trigger.new);
}

パフォーマンスチューニングについては、SOQLクエリやDML操作の回数を可能な限り少なくすること、ループの中でこれらの操作を行わないことが鍵になります。

バージョン管理と変更履歴

コードの変更を管理し、開発チーム間でコードの整合性を保持するためにはバージョン管理システムを使用することが推奨されます。

例えば、Gitを使用し、変更ごとのコミットで、変更履歴を確実に追跡しましょう。

git add MyTrigger.cls
git commit -m ""Added error handling for Account Trigger""
git push

このようにして、各変更を綺麗に記録し、チームメンバーがどのような変更を加えたかを簡単に追跡できるようになります。

まとめ

当記事の内容をまとめます。

  • Apexトリガーの基本
  • 開発から応用
  • ベストプラクティス
  • トラブルシューティング
  • SalesforceのApexトリガー

適切な理解と実務適用により、ApexトリガーはSalesforceプラットフォームでのビジネスプロセスの効率化、データ整合性の維持、ユーザーエクスペリエンスの向上に大きく貢献します。

常にベストプラクティスを念頭に置きながら、コードを書き、テストし、デプロイすることを心がけましょう。

タイトルとURLをコピーしました