SalesforceでRecord Typeを動的に取得および利用する方法


SalesforceでRecord Typeを動的に取得および利用する方法

Salesforceでは、Record Typeを正確に取得するための戦略が重要です。特にAppExchangeアプリのような強力なアプリケーションを開発する際には、IDやNameを直接参照するのではなく、DeveloperNameを使用してRecord Typeを識別することが推奨されます。以下に、Record Typeを動的に取得し、環境やユーザー設定に依存しない方法を詳しく説明します。


1. なぜDeveloperNameを使用するのか

  • Idの問題: Record TypeのIDは環境ごとに異なるため、特定のIDに依存するコードは移植性がありません。
  • Nameの問題: Nameはユーザーの言語やローカライズ設定に基づいて変化するため、信頼できる識別子として使用できません。
  • DeveloperNameの利点: 変更不可能な一意の識別子であり、どの環境でも同じ値を保持します。

2. 動的なRecord Type取得メソッド

以下は、指定したオブジェクトの利用可能なRecord TypeをDeveloperNameで動的に取得するユーティリティメソッドの例です。このメソッドはキャッシュを活用して効率を向上させています。

public class Utils {
    // Record types cache
    private static Map<Schema.SObjectType, Map<String, Id>> rtypesCache;
    private static List<SObject> results;

    static {
        rtypesCache = new Map<Schema.SObjectType, Map<String, Id>>();
        results = new List<SObject>();
    }

    /**
     * 指定されたオブジェクトタイプの利用可能なRecordTypeを取得する
     * @param token Schema.SObjectType
     * @return Map<String, Id> DeveloperNameをキーとするRecordType IDのマップ
     */
    public static Map<String, Id> getRecordTypeMapForObjectGeneric(Schema.SObjectType token) {
        // キャッシュ確認
        Map<String, Id> mapRecordTypes = rtypesCache.get(token);
        if (mapRecordTypes != null) {
            return mapRecordTypes;
        }

        mapRecordTypes = new Map<String, Id>();
        rtypesCache.put(token, mapRecordTypes);

        // Describe情報を取得
        Schema.DescribeSObjectResult obj = token.getDescribe();

        // RecordTypeをSOQLで取得
        if (results.isEmpty()) {
            String soql = 'SELECT Id, DeveloperName, sObjectType FROM RecordType WHERE IsActive = TRUE';
            try {
                results = Database.query(soql);
            } catch (Exception ex) {
                results = new List<SObject>();
            }
        }

        // RecordTypeInfoを取得し、ユーザーに利用可能なものをフィルタリング
        Map<Id, Schema.RecordTypeInfo> recordTypeInfos = obj.getRecordTypeInfosByID();
        for (SObject rt : results) {
            if (recordTypeInfos.containsKey(rt.Id) && recordTypeInfos.get(rt.Id).isAvailable()) {
                mapRecordTypes.put(String.valueOf(rt.get('DeveloperName')), rt.Id);
            }
        }

        return mapRecordTypes;
    }
}

3. 使用例

以下のコードは、`Account`オブジェクトのRecord Typeを動的に割り当てる例です。

// Utilsクラスを使用してAccountのRecordTypeを取得
Map<String, Id> accountTypes = Utils.getRecordTypeMapForObjectGeneric(Account.SObjectType);

// 各RecordTypeのDeveloperNameとIdをデバッグ出力
for (String developerName : accountTypes.keySet()) {
    System.debug('RecordType DeveloperName: ' + developerName + ', Id: ' + accountTypes.get(developerName));
}

// 特定の条件に基づいてRecordTypeを利用
if (accountTypes.containsKey('Really_Stinking_Big_Account')) {
    System.debug('RecordType "Really_Stinking_Big_Account" is available with Id: ' + accountTypes.get('Really_Stinking_Big_Account'));
} else {
    System.debug('RecordType "Really_Stinking_Big_Account" is not available.');
}

4. この方法の利点

  1. 移植性の高さ: DeveloperNameを使用することで、どの環境でも正確にRecord Typeを特定可能。
  2. ユーザーや環境に依存しない: `isAvailable`プロパティを活用して、実行中のユーザーに利用可能なRecord Typeのみを使用。
  3. AppExchange対応: 動的SOQLを利用するため、Record TypeをサポートしないProfessional EditionやGroup Editionにも対応。
  4. パフォーマンス: キャッシュを利用してクエリ回数を削減。

まとめ

このアプローチにより、Salesforceアプリは柔軟性と堅牢性を備えた設計が可能になります。特に複雑な権限管理や多言語対応が求められる場合に効果的です。

コメント