【Salesforce】カスタムメタデータのはじめかた

# はじめに
この記事では、[カスタムメタデータ](https://help.salesforce.com/s/articleView?id=sf.custommetadatatypes_overview.htm&type=5)について解説します。
汎用性が高く知っているとかなり便利なんですが、得体が知れず若干取っ付きづらい、、という方も多いと思います。
そこで、基本的な使い方・注意点や活用法など、カスタムメタデータを使うための基礎知識について説明していきます！

# 目次
- [1. カスタムメタデータとは](#1-カスタムメタデータとは)
- [2. 作成方法](#2-作成方法)
- [3. 基本的な使い方](#3-基本的な使い方)
- [4. レコードの一括作成](#4-レコードの一括作成)
- [5. おわりに](#5-おわりに)

# 1. カスタムメタデータとは
ざっくり言うと小さなオブジェクトです。
そのため複数選択リストや数式などの項目が作成できない、レコードタイプが存在しないなど、通常のオブジェクトに比べると機能が制限されています。
ただ、それを補って余りある（と個人的に思う）メリットを2つ紹介します。

### 【1】レコードのリリースが可能
Sandbox環境で作成したレコードを別環境に反映させる際は、通常のオブジェクトだとデータローダ等のツールを使用して反映を行います。
しかし、カスタムメタデータであれば「レコードデータそのもの」を変更セットやCLIでのリリースに含めることができるため、全環境で同じデータを使用できます。
例えば「都道府県マスタ」など、更新頻度が非常に低いデータに関してはカスタムメタデータで作成した方が便利かもしれません。

### 【2】SOQLでアクセスし放題（一部例外あり）
ガバナ制限の1つである「SOQLクエリの発行数は100回まで」、これがカスタムメタデータであれば基本的にガバナ制限の対象外となります[^1]。
そのため通常ではご法度な、ループ内でのSOQLクエリ発行をしても怒られません。

```java
for(Account acc : accountList){
    SampleMetaData__mdt md = [SELECT Id, SampleField__c FROM SampleMetaData__mdt WHERE DeveloperName = :acc.Sample__c LIMIT 1];
    acc.Hoge__c = md.SampleField__c;
}
```

# 2. 作成方法

###【1】カスタムメタデータの作成

設定 → カスタムメタデータ型 → 新規カスタムメタデータ型を選択し、ラベルとAPI名を入力して保存
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573865/05cd5918-d40b-20b1-c893-55f3cb88c5ad.png)

###【2】カスタム項目の作成

対象のカスタムメタデータ → カスタム項目セクションの「新規」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573865/9cc9385e-1917-9a40-1635-5918a6b228ca.png)

今回はテキスト型を指定し、ラベル・文字数・API名のみ入力して保存
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573865/1e525b9a-448e-579b-844e-a864bf6bbb77.png)

###【3】レコードの作成

設定 → カスタムメタデータ型 → レコードの管理 → 「新規」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573865/e3022386-9273-eb93-24da-1b0ec1e3c83a.png)

ラベル・API名・カスタム項目を入力して保存
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573865/64267a1d-ac6a-fe6b-a55d-70316a8094d9.png)


以上でカスタムメタデータ・項目の作成とレコードの登録が完了です！


# 3. 基本的な使い方

ここではApexからカスタムメタデータを取得する方法を解説します。

###【1】1件ずつ取得

```java
// SOQLで取得
SampleMetaData__mdt md1 = [SELECT Id, DeveloperName, MasterLabel, Language, NamespacePrefix, Label, QualifiedApiName, SampleField__c FROM SampleMetaData__mdt WHERE DeveloperName = 'TestA'];
// レコードIDで取得
SampleMetaData__mdt md2 = SampleMetaData__mdt.getInstance('m005h000000Sl7vAAC');
// レコード名で取得
SampleMetaData__mdt md3 = SampleMetaData__mdt.getInstance('TestA');

// 結果
// SampleMetaData__mdt:{SampleField__c=aaa, Label=テストA, MasterLabel=テストA, Language=ja, QualifiedApiName=TestA, Id=m005h000000Sl7v, DeveloperName=TestA, NamespacePrefix=null}
```

IDやレコード名以外で条件指定を行うのでなければ、組み込みの`getInstance()`を使用して取得すればOKです。

###【2】全件取得

```java
// SOQLで取得
List<SampleMetaData__mdt> md1 = [SELECT Id, DeveloperName, MasterLabel, Language, NamespacePrefix, Label, QualifiedApiName, SampleField__c FROM SampleMetaData__mdt];
// Map型で取得
Map<String, SampleMetaData__mdt> md2 = SampleMetaData__mdt.getAll();
// List型へ代入
List<SampleMetaData__mdt> md3 = SampleMetaData__mdt.getAll().Values();
```

こちらも基本的には組み込みの`getAll()`を使用すればOKです。
しかし`getAll()`で取得した場合、ロングテキストエリア項目を255文字までしか取得できません。
ロングテキストエリア項目を使用する場合に限っては必ずSOQLで取得しましょう。

[カスタムメタデータ型のメソッド](https://developer.salesforce.com/docs/atlas.ja-jp.234.0.apexcode.meta/apexcode/apex_methods_system_custom_metadata_types.htm#apex_System_CustomMetadataType_getinstance_apiName)[^2]

# 4. レコードの一括作成

カスタムメタデータのレコード登録・更新はデータローダやインポートウィザードでは行えないため、画面上からは1件1件手動で登録するしかありません。
CLIからであれば一括作成できますが、ハードルが高いと感じる方も多いと思います。
しかし、大変有り難いことに画面上からcsvファイルを元にレコードの登録・更新が行える、`CustomMetadataLoader`というパッケージがあります。

https://github.com/forcedotcom/CustomMetadataLoader

そしてこの`CustomMetadataLoader`のインストール・使用方法について解説されている記事があるので、ここでは紹介のみとさせていただきます。

https://qiita.com/Aptenodytes9/items/ebf059fe35aea153b494

[^1]: ロングテキストエリアを含むレコードや、フローからのアクセス時は[ガバナ制限の対象です。](https://help.salesforce.com/s/articleView?id=sf.custommetadatatypes_limits.htm&type=5)
[^2]: `getAll()`関数の説明に「対応付けのキーはレコードのID」と記載されていますが、実際は「レコード名(DeveloperName)」なので注意してください。

# 5. おわりに

カスタムメタデータの基本的な解説は以上となります。
個人的には、「選択リスト値やレコードタイプAPI名をメタデータのレコードに登録し、Apex側でレコードを呼び出してカスタム項目の値を使用する」パターンが多いです。

- 行動の「件名」選択リスト値とそれに対するテキスト項目をレコードへ登録し、beforeInsertトリガでオブジェクトのカスタム項目に値を入れ込む
- 取引先のレコードタイプ名とそれに対するチェックボックス項目をレコードへ登録し、beforeInsertトリガでオブジェクトのカスタム項目に反映させる
- 選択リスト値とそれに対するレコードタイプ名をレコードをへ登録し、beforeInsertトリガでレコードタイプIDを取得して割り当てる
- プロファイル名とそれに対するエラーメッセージをレコードへ登録し、表示するエラーメッセージをプロファイル毎に出し分ける

通常であればApex側でMapやIF文で行う処理の分岐を、カスタムメタデータで代替するイメージです。
コードの可読性が上がるだけでなく、値のマッピングはメタデータで行っているため本番環境にリリース済であっても変更や修正が容易です。
上記のようなシンプルなパターンだとあまり有用性を感じられないかもしれませんが、選択リスト値やレコードタイプによって処理の分岐が大きく変動する時は非常に役立ちます。

活用法は無限大（？）なので、今後はぜひカスタムメタデータの使用を検討してみてください！

## 参考
- [コードを使用した Salesforce の拡張：カスタムメタデータ型](https://help.salesforce.com/s/articleView?id=sf.custommetadatatypes_overview.htm&type=5)
- [Apex 開発者ガイド：カスタムメタデータ型のメソッド](https://developer.salesforce.com/docs/atlas.ja-jp.234.0.apexcode.meta/apexcode/apex_methods_system_custom_metadata_types.htm)
- [Qiita：Salesforceでカスタムメタデータ型を大量INSERTする方法](https://qiita.com/Aptenodytes9/items/ebf059fe35aea153b494)