Salesforce基礎
Salesforceの開発に必要な基本概念をまとめています。
ClassLabの実例を交えて、オブジェクト・Apex・SOQL・ガバナ制限まで体系的に解説します。
前提: プログラミングの基礎知識があること
MoveIn__c、ServiceGuide__c等)を使用しています。
1. オブジェクトと項目
標準/カスタム、リレーション
2. レコードタイプ
ページレイアウト
3. 入力規則
Validation Rules
4. フロー
Flow Builder
5. Apexの基礎
クラス、トリガー
6. SOQL
クエリ言語
7. 実行順序
非常に重要
8. ガバナ制限
制限値と対策
📦 1. オブジェクトと項目
オブジェクトとは
データベースの「テーブル」に相当する概念です。Salesforceでは標準オブジェクトとカスタムオブジェクトの2種類があります。
| 種類 | 説明 | 例 |
|---|---|---|
| 標準オブジェクト | Salesforceが標準提供 | Account, Contact, Opportunity |
| カスタムオブジェクト | 独自に作成(末尾に __c) | MoveIn__c, ServiceGuide__c |
項目(フィールド)
| 項目タイプ | 説明 | CL例 |
|---|---|---|
| テキスト | 文字列 | LastName__c(姓) |
| 数値 | 数値 | CumulativeNumber__c(累計架電数) |
| 日付 | 日付 | MoveInDate__c(入居予定日) |
| 選択リスト | 選択肢 | Satus__c(架電状況) |
| 参照関係(Lookup) | 他オブジェクトへのリンク | IntroductionFor__c → Account |
| 主従関係(Master-Detail) | 親子の強い紐付け | ServiceGuide__c → MoveIn__c |
| 数式 | 計算結果を自動表示 | MoveIn_LastName__c |
| 通貨 | 金額 | Amount__c(金額) |
| チェックボックス | true/false | ElecProhibited__c |
参照関係 vs 主従関係
| 特徴 | 参照関係(Lookup) | 主従関係(Master-Detail) |
|---|---|---|
| 親の削除時 | 子はそのまま残る | 子も一緒に削除される |
| 必須 | 任意にできる | 常に必須 |
| 積み上げ集計 | 使えない | 使える |
| CL例 | MoveIn__c → Account | ServiceGuide__c → MoveIn__c |
オブジェクトと項目の補足情報
カスタムオブジェクトのAPI名は必ず __c サフィックスが付きます。カスタム項目も同様です。リレーション名にはサブクエリ時に __r サフィックスを使用します。
- オブジェクト:
MoveIn__c - 項目:
MoveInDate__c - リレーション:
ServiceGuides__r(サブクエリ用)
📋 2. レコードタイプとページレイアウト
レコードタイプ
1つのオブジェクトで異なるプロセスやデータ種別を管理する仕組みです。レコードタイプごとに選択リスト値やページレイアウトを切り替えることができます。
ページレイアウト
レコード画面に表示する項目の配置を定義します。レコードタイプとプロファイルの組み合わせで、ユーザーごとに表示される項目・セクションを制御できます。
レコードタイプの活用例
例えば「受注」オブジェクトで「販売」と「リース」の2種類のレコードタイプを作成すると、それぞれのビジネスプロセスに合わせた項目配置やピックリスト値の制御が可能になります。
✅ 3. 入力規則(Validation Rules)
「エラーになる条件」を書くという点に注意してください。
よく使う関数
| 関数 | 用途 | 例 |
|---|---|---|
ISBLANK() | 空白チェック | ISBLANK(LastName__c) |
ISCHANGED() | 値の変更チェック | ISCHANGED(Satus__c) |
ISNEW() | 新規レコードかチェック | ISNEW() |
AND() / OR() | 複数条件の結合 | AND(ISBLANK(x), ISBLANK(y)) |
PRIORVALUE() | 変更前の値を取得 | PRIORVALUE(Satus__c) |
🔄 4. フロー(Flow)
| 種類 | 起動タイミング | CL例 |
|---|---|---|
| レコードトリガーフロー(Before) | レコード保存前 | MoveInFlowBeforeSaved |
| レコードトリガーフロー(After) | レコード保存後 | MoveInFlow, AfterCallSendMessage |
| 画面フロー | ユーザーが画面から実行 | - |
| スケジュールフロー | 定期実行 | - |
フローの使い分けガイド
Before Save フロー: 同一レコードの項目値を設定する場合に使用。DMLなしで高速。
After Save フロー: 関連レコードの作成・更新や外部連携が必要な場合に使用。
画面フロー: ウィザード形式の入力画面を作成する場合に使用。
💻 5. Apexの基礎
基本構文
public class MyService {
public static List<Account> getAccounts() {
return [SELECT Id, Name FROM Account LIMIT 10];
}
}
トリガー
trigger MyTrigger on MoveIn__c (before insert, after insert) {
if (Trigger.isBefore && Trigger.isInsert) {
// 保存前の処理
}
if (Trigger.isAfter && Trigger.isInsert) {
// 保存後の処理
}
}
トリガーイベント
| イベント | タイミング | 用途 |
|---|---|---|
before insert | 新規レコード保存前 | 値の設定、バリデーション |
after insert | 新規レコード保存後 | 関連レコードの作成 |
before update | 更新前 | 値の変更、バリデーション |
after update | 更新後 | 関連レコードの更新 |
before delete | 削除前 | 削除可否チェック |
after delete | 削除後 | 関連データのクリーンアップ |
トリガーのベストプラクティス
トリガーにはロジックを直接書かず、ハンドラクラスに委譲するパターンが推奨されます。1オブジェクトにつきトリガーは1つにし、コンテキスト変数(Trigger.isBefore, Trigger.isAfter等)で処理を分岐させます。
🔍 6. SOQL
SELECT Id, Name, MoveInDate__c FROM MoveIn__c WHERE Satus__c = '架電済み' ORDER BY MoveInDate__c DESC LIMIT 100
よく使うパターン
List<MoveIn__c> moveIns = [
SELECT Id, Name
FROM MoveIn__c
WHERE Id = :targetId
];
List<MoveIn__c> moveIns = [
SELECT Id, Name,
(SELECT Id, type__c, AgencyStatus__c FROM ServiceGuides__r)
FROM MoveIn__c
WHERE Id = :targetId
];
AggregateResult[] results = [
SELECT COUNT(Id) cnt, Satus__c
FROM MoveIn__c
GROUP BY Satus__c
];
⚡ 7. Salesforceの実行順序
標準実行順序
Step 1 System Validation
システム標準のバリデーション(必須チェック、データ型チェック等)
Step 2 Before Triggers
Apexの before insert / before update トリガーが実行される
Step 3 Custom Validation Rules
カスタム入力規則が評価される
Step 4 After Triggers
Apexの after insert / after update トリガーが実行される
Step 5 Flows
レコードトリガーフロー(After Save)が実行される
CL環境の実行順序例(MoveIn__c INSERT)
実行順序に関する注意事項
Before Triggerで値を変更した場合、その変更はCustom Validation Rulesの評価対象になります。After Triggerで同じレコードを更新すると再帰処理が発生する可能性があるため、静的変数等で再帰防止を実装する必要があります。
🛡️ 8. ガバナ制限
| 制限 | 同期 | 非同期 | 対策 |
|---|---|---|---|
| SOQLクエリ数 | 100 | 200 | ループ内でSOQLを書かない |
| SOQL取得レコード数 | 50,000 | 50,000 | LIMIT句をつける |
| DMLステートメント数 | 150 | 150 | リストでまとめてDML |
| DMLレコード数 | 10,000 | 10,000 | バッチ処理で分割 |
| CPU時間 | 10秒 | 60秒 | Mapでネストループ削減 |
| ヒープサイズ | 6MB | 12MB | 不要な変数を解放 |
バルク処理の比較
ループ内でSOQL/DML
ループ外でまとめて実行
NG例:
// NG: ループ内でSOQLを実行するとガバナ制限に抵触
for (MoveIn__c mi : Trigger.new) {
List<ServiceGuide__c> sgs = [
SELECT Id FROM ServiceGuide__c WHERE MoveIn__c = :mi.Id
];
}
OK例:
// OK: ループ外でまとめてSOQL
Set<Id> moveInIds = new Set<Id>();
for (MoveIn__c mi : Trigger.new) {
moveInIds.add(mi.Id);
}
List<ServiceGuide__c> sgs = [
SELECT Id, MoveIn__c
FROM ServiceGuide__c
WHERE MoveIn__c IN :moveInIds
];
⚙️ 9. バッチ処理
大量データの処理や定期実行ジョブに使用します。バッチサイズごとにトランザクションが分割されるため、ガバナ制限を回避できます。
バッチ処理の流れ
Database.executeBatch() で起動start() で処理対象のクエリを返す(1回のみ)execute() でバッチサイズごとに処理(複数回)finish() で完了処理(1回のみ)global class MyBatch implements Database.Batchable<sObject>, Schedulable {
// スケジュール実行用
global void execute(SchedulableContext sc) {
Database.executeBatch(new MyBatch(), 1);
}
// 処理対象のクエリを返す
global Database.QueryLocator start(Database.BatchableContext bc) {
return Database.getQueryLocator('SELECT Id FROM MoveIn__c');
}
// バッチサイズごとに実行
global void execute(Database.BatchableContext bc, List<MoveIn__c> scope) {
// 処理ロジック
}
// 完了時に1回実行
global void finish(Database.BatchableContext bc) {
// 後処理
}
}
バッチ処理のTips
Database.executeBatch() の第2引数でバッチサイズを指定できます(デフォルト200)。外部連携がある場合はバッチサイズを小さくしてコールアウト制限を回避します。Database.Stateful インターフェースを実装すると、execute間で変数の状態を保持できます。