Apexでよく使うSchema.系の静的と動的の記述比較

この記事は [Salesforce Platform Advent Calendar 2019 - Qiita](https://qiita.com/advent-calendar/2019/salesforce-platform) 第4日目の投稿です。

# はじめに

**Apexでよく使うSchema.系のお話**

Salesforceでは、データを取得するにはSOQLのクエリなどで取得しますが、
データではなく、オブジェクトや項目の情報を取得する際には、Schemaを使用し取得します。
初歩的なお話ではありますが、よく使う割にいつも書き方を忘れるので、まとめてみました。

# 使用するケース
**・オブジェクトや項目の表示ラベルを取得**
**・カスタム項目かどうかを判定**
**・選択リスト値を取得**
**・レコードタイプIDを取得**

などなど

# 取引先の「種別」の表示ラベルを取得する例

### 動的な書き方
```
Schema.getGlobalDescribe().get('Account').getDescribe().fields.getMap().get('Type').getDescribe().getLabel()
```

### 静的な書き方
```
Schema.SObjectType.Account.fields.Type.getLabel() // パターン1
Account.Type.getDescribe().getLabel()             // パターン2
```


うーん、動的に書くと長い。。
**ひとつずつ紐解いていきましょー！！**


# 全オブジェクトを取得
```
Schema.getGlobalDescribe()
```

**使い方**

```Map<String, Schema.SObjectType> soMap = Schema.getGlobalDescribe();```


# 全オブジェクトから指定したオブジェクトを取得
```
Schema.getGlobalDescribe().get('Account')
```

**使い方**

```Schema.SObjectType st = Schema.getGlobalDescribe().get('Account');```
```Schema.SObjectType st = Account.getSObjectType(); // SObjectTypeを取得するのでgetSObjectTypeでも取得可```

# SObjectの情報を取得
```
Schema.getGlobalDescribe().get('Account').getDescribe() // 動的な記述
Schema.SObjectType.Account                              // 静的な記述 パターン1
Account.getSObjectType().getDescribe()                  // 静的な記述 パターン2
```

**使い方**
```Schema.DescribeSObjectResult dsr = Schema.getGlobalDescribe().get('Account').getDescribe();```
```Schema.DescribeSObjectResult dsr = Schema.SObjectType.Account;```
```Schema.DescribeSObjectResult dsr = Account.getSObjectType().getDescribe();```

**DescribeSObjectResultからオブジェクトの情報を取得できる**

**例**

```
dsr.getLabel(); // オブジェクトの表示ラベルをStringで取得
dsr.isCustom(); // カスタムオブジェクトならTrue
dsr.getRecordTypeInfosById(); // 取引先に関連するレコードタイプIDをMapで取得
などなど
```

[Apex 開発者ガイド：DescribeSObjectResult クラス](https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_methods_system_sobject_describe.htm)

# 指定したSObjectの全項目を取得
```
Schema.getGlobalDescribe().get('Account').getDescribe().fields
Schema.SObjectType.Account.fields
```

**使い方**
アクセス不可。fieldsの後には項目メンバー変数名またはgetMapメソッドが続きます。


# 指定したSObjectの全項目を取得
```
Schema.getGlobalDescribe().get('Account').getDescribe().fields.getMap() // 動的な記述
Schema.SObjectType.Account.fields.getMap()                              // 静的な記述
```

**使い方**
```Map<String, Schema.SObjectField> fMap = Schema.getGlobalDescribe().get('Account').getDescribe().fields.getMap();```
```Map<String, Schema.SObjectField> fMap = Schema.SObjectType.Account.fields.getMap();```


# 全項目から指定した項目の情報を取得
```
Schema.getGlobalDescribe().get('Account').getDescribe().fields.getMap().get('Type').getDescribe() // 動的な記述
Schema.SObjectType.Account.fields.Type       // 静的な記述 パターン1
Account.Type.getDescribe()                   // 静的な記述 パターン2
```

**使い方**
```Schema.DescribeFieldResult dfr = Schema.getGlobalDescribe().get('Account').getDescribe().fields.getMap().get('Type').getDescribe();```
```Schema.DescribeFieldResult dfr = Schema.SObjectType.Account.fields.Type;```
```Schema.DescribeFieldResult dfr = Account.Type.getDescribe();```

**DescribeFieldResultから項目の情報を取得できる**

**例**

```
dfr.getLabel(); // 項目の表示ラベルをStringで取得
dfr.getType(); // 項目のデータ型を取得
dfr.getPicklistValues(); // 選択リストの値を取得
などなど
```

[Apex 開発者ガイド：DescribeFieldResult クラス](https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_methods_system_fields_describe.htm)



### ↓　てことで、はじめのようになる　↓


### 動的な書き方
```
Schema.getGlobalDescribe().get('Account').getDescribe().fields.getMap().get('Type').getDescribe().getLabel()
```

### 静的な書き方
```
Schema.SObjectType.Account.fields.Type.getLabel() // パターン1
Account.Type.getDescribe().getLabel()             // パターン2
```



# 動的な記述にすることで便利な共通メソッドを使用可能
## レコードタイプIDを取得する場合
**オブジェクト名とレコードタイプ名を文字列で渡すだけでIDを取得できるメソッド**

```java
    // レコードタイプIDをdeveloperNameで取得
    public static Id getRecordtypeId(String objName, String developerName) {
        return Schema.getGlobalDescribe().get(objName).getDescribe().getRecordTypeInfosByDeveloperName().get(developerName).getRecordTypeId();
    }
```

**使い方**
```Id recId = getRecordtypeId('Account', 'TestRecordType1');```


※レコードタイプIDの取得などは下記のSOQLで取得可能だが、
　SELECT回数のガバナ制限にカウントされるため、上記Schemaにて取得するほうが良い

```Id recId = [SELECT Id FROM RecordType WHERE SObjectType = 'Account' and DeveloperName = 'TestRecordType1'];```


## 選択リストの値を取得する場合
**オブジェクト名と項目名を文字列で渡すだけで選択リストのListを取得できるメソッド**

```java
    // 選択リスト項目の選択肢の値を取得
    public static List<String> getPicklistValues(String objName, String fieldName) {
        List<Schema.PicklistEntry> ple = Schema.getGlobalDescribe().get(objName).getDescribe().fields.getMap().get(fieldName).getDescribe().getPicklistValues();
        List<String> sList = new List<String>();
        for (Schema.PicklistEntry p : ple) {
            sList.add(String.valueOf(p.getLabel())); // 表示ラベル
         // sList.add(String.valueOf(p.getValue())); // API参照名
        }
        return sList;
    }
```

**使い方**

```List<String> plvList = getPicklistValues('Account', 'Type');```

# まとめ

Apexを書いていてSchemaを使ったことがない人はほとんどいないはず。
ただ書き方いっぱいあるから、混乱してる人もいるはず。
こんなもん開発者ガイドを見りゃいいやん、な話だけど、
開発者ガイドって理解し辛いんだもん。。
ってことで今回は、Schema.系の書き方、いつも忘れちゃうので、まとめてみました。