Apexにつかわれているオブジェクト項目の調査2 (SFDX) 

### 要件
Apex,Trigger,Flowが使われているオブジェクト項目を洗い出したい

### 参照
Workbenchで調査
https://qiita.com/richard_hcq/items/6b627e6383b6115675f4
詳細資料
https://blog.bessereau.eu/assets/pdfs/api_tooling.pdf
　※ワークルールについて
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/801991/5ff5998e-f325-230d-eee6-da7aa57df2a9.png)


### 案
VsCodeでSfdxコマンドからToolingApiのSoqlから関連情報のCsvを出力する
関連オブジェクト
MetadataComponentDependencyから依存項目をみれますが、なんのオブジェクトの項目かを調べるため、CustomObjectとCustomFiledの内容をダウロードし、突き合わせる必要がある
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/801991/020fc92c-cf69-7263-ce82-55011b0e7df4.png)
上記の例で、バッチがRmBusinessSectionListの法人番号をつかっていることがわかる。

### 実施ポイント
#### ①　MetadataComponentDependencyの実施Soql
```
sfdx force:data:soql:query -q  
"select MetadataComponentId,MetadataComponentName,MetadataComponentType,
RefMetadataComponentId,RefMetadataComponentName,RefMetadataComponentType
from MetadataComponentDependency 
where MetadataComponentType in ('ApexClass') and 
RefMetadataComponentType in ('CustomField','CustomObject','ApexClass')  
Order by MetadataComponentName" -r csv -t >ApexAndField.csv
```
※　-t --toolingapi　このオプションはSfdxで使える。Dataloaderはまた使えないようです。
　　　　ちなみにDeveloperコンソールのQueryに使える（Optionにチェックする）
　　該当関係オブジェクトは一Queryで２０００行の制御がある。
※　TriggerまたFlowの場合、 MetadataComponentType in ('ApexTrigger','Flow')
※　別のオブジェクトで下記設定で、２０００行以上が取れるが、 
    MetadataComponentDependencyができない
　　<Font color=red> sfdx config:set maxQueryLimit=20000000 </Font>
　　取引先の200万レコードがとりますが、遅くて１時間以上がかかってしまった。
　　　（select id from account)
※　漢字名がある場合、VsCodeのTerminalで文字ばけ、普通のCmdのPromptで実行する

結果：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/801991/6a49c5e6-d73e-93e6-cfb4-4ff30d026d50.png)

Apexと使われている項目の一覧ができました。

#### ②　上記①に項目は何のオブジェクトの項目は下記二つ情報が必要です。
##### カスタムオブジェクト一覧
```
select 
  Id,DeveloperName,NamespacePrefix 
from CustomObject 
where NamespacePrefix = null 
Order by DeveloperName
```
※「NamespacePrefix = null」は別Packageのものを除外している

　　実行コマンド
```
sfdx force:data:soql:query -q  "select Id,DeveloperName,NamespacePrefix from CustomObject where NamespacePrefix = null Order by DeveloperName" -r csv -t >CustomObject.csv
```

##### カスタム項目一覧
```
select 
  Id,DeveloperName,NamespacePrefix,TableEnumOrId 
from CustomField 
where NamespacePrefix = null 
```
　　実行コマンド
```
sfdx force:data:soql:query -q  "select Id,DeveloperName,NamespacePrefix,TableEnumOrId from CustomField where NamespacePrefix = null Order by TableEnumOrId" -r csv -t >CustomField.csv

```
##### ※補足　Flow & ProcessBuilder
```
sfdx force:data:soql:query -q  "select Id ,DefinitionId,Status,ProcessType,VersionNumber from Flow where Status in ('Active') Order by MasterLabel" -r csv -t >Flow.csv

```
##### ※補足　ApexTrigger
```
sfdx force:data:soql:query -q  "select Id,Name,NamespacePrefix from ApexTrigger Order by Name" -r csv -t >ApexTrigger.csv

```
##### ※補足 WorkflowRule 
```
 sfdx force:data:soql:query -q  "select Id,ManageableState,Name,TableEnumOrId from WorkflowRule" -r csv -t >workflowrule.csv
```
##### ※補足　WorkflowFieldUpdate
```
sfdx force:data:soql:query -q  "select Id,Name,EntityDefinitionId,FieldDefinitionId,LiteralValue,LookupValueId,SourceTableEnumOrId from WorkflowFieldUpdate" -r csv -t >WorkflowFieldUpdate.csv
```

#### 関係マットリックス
上記三つ情報はExcelシートに張り付け、マクロで突き合わせで、Apexが横並べ、縦はオブジェクト、項目を並べ、使われているところに「O」をつけ、関係マットリックスが作成できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/801991/02ae91a7-3d06-49a1-b92e-eb675e45ed2f.png)

##### VBA Macro
```
Sub fillApexName()
  Set rfSht1 = Sheets("CustomObject")
  Set rfSht2 = Sheets("CustomField")
  Set srcSht = Sheets("ApexAndApexField")
  
  Set objDic = CreateObject("Scripting.Dictionary")
  Set fieldDic = CreateObject("Scripting.Dictionary")
  Set MatrixDicX = CreateObject("Scripting.Dictionary")
  Set MatrixDicY = CreateObject("Scripting.Dictionary")
  
  'obj
  ii = 3
  While rfSht1.Cells(ii, 2).Value <> ""
    objDic.Add rfSht1.Cells(ii, 2).Value, rfSht1.Cells(ii, 3).Value
    ii = ii + 1
  Wend
  
  'field
   ii = 3
  While rfSht2.Cells(ii, 2).Value <> ""
    vv = rfSht2.Cells(ii, 5).Value
    If Left(vv, 1) = "0" Then
      fieldDic.Add rfSht2.Cells(ii, 2).Value, objDic.Item(vv)
    Else
      fieldDic.Add rfSht2.Cells(ii, 2).Value, vv
    End If
    ii = ii + 1
  Wend
 
  'MatrixDicX
  'MatrixDicY
   ii = 3
   xcol = 6
   yrow = 4
  While srcSht.Cells(ii, 2).Value <> ""
    'x col
    vv = srcSht.Cells(ii, 3).Value
    If Not MatrixDicX.Exists(vv) Then
      MatrixDicX.Add vv, xcol
      xcol = xcol + 1
    End If
    
    'yrow
    tp = srcSht.Cells(ii, 7).Value
    fn = srcSht.Cells(ii, 6).Value
    fid = srcSht.Cells(ii, 5).Value
    If tp = "CustomField" Then
      key1 = tp & "#" & fieldDic.Item(fid) & "#" & fn
      
    Else
      If tp = "ApexClass" Then
        key1 = tp & "#" & fn & "#"
      End If
    End If
    If Not MatrixDicY.Exists(key1) Then
      MatrixDicY.Add key1, yrow
      yrow = yrow + 1
    End If

    
    ii = ii + 1
  Wend
  
  'xy
  Set ToSht = Sheets("MatrixApex")
  ToSht.Range("A4:AAX20000").ClearContents
  ToSht.Range("E3:AAX3").ClearContents
  'ii = 4
 
  For Each vKey In MatrixDicY
    
    item2 = MatrixDicY.Item(vKey)
    arr = Split(vKey, "#")
    ToSht.Cells(item2, 2) = arr(0)
    ToSht.Cells(item2, 3) = arr(1)
    ToSht.Cells(item2, 4) = arr(2)
 Next
 
 'x-ray
 For Each vKey In MatrixDicX
    item2 = MatrixDicX.Item(vKey)
    ToSht.Cells(3, item2) = vKey
 Next
 
 'mark the point
   ii = 3
   xcol = 6
   yrow = 4
  While srcSht.Cells(ii, 2).Value <> ""
    'x col
    apx = srcSht.Cells(ii, 3).Value
    
    'yrow
    tp = srcSht.Cells(ii, 7).Value
    fn = srcSht.Cells(ii, 6).Value
    fid = srcSht.Cells(ii, 5).Value
    If tp = "CustomField" Then
      key1 = tp & "#" & fieldDic.Item(fid) & "#" & fn
      
    Else
      If tp = "ApexClass" Then
        key1 = tp & "#" & fn & "#"
      End If
    End If
    
    ToSht.Cells(MatrixDicY.Item(key1), MatrixDicX.Item(apx)).Value = "O"

    
    ii = ii + 1
  Wend

    
  
 MsgBox ("Apex and field mapping OK")
  
  
End Sub
```