Salesforce
Apex
Visuaoforce

Apexでネスト(入れ子)のMapを使う時によくやる奴

More than 1 year has passed since last update.

入れ子のMapをよく使います。で、良くハマります。以下は備忘録。

Mapに存在しないキーで呼び出すとエラーが出る

VisualforceでMapに存在しないキーで呼び出すとエラーがでるので注意しましょう。
呼び出す可能性があるキーはまずMapに突っ込んでおかないと駄目です。
よくやるのが、年月のテーブルです。

名前 4月 5月 6月 7月 8月 9月 10月 11月 12月 1月 2月 3月
C1 100 200 300 400 500 600 700 800 900 1000 1100 1200
C2 1200 1100 1000 900 800 700 600 500 400 300 200 100

こういうテーブルを作りたい時に入れ子Mapを使うのですが、その場合は最初に全てのキーを突っ込んでおきます。

Apexクラス
public Map<String,Map<Integer,Integer>> monthlyMap{get;set;}
LIST<String> keyName = new LIST<String>();
keyName.add('C1','C2'); //カテゴリ名みたいなモノ
LIST<Integer> intM = new LIST<Integer>();
intM.add(4,5,6,7,8,9,10,11,12,1,2,3);//月
for(String k : keyName){//カテゴリ名でループ
    Map<Integer,Integer> innerMap = new Map<Integer,Integer>();
    for(Integer i :intM){//内部Map用のデータを生成
        innerMap.put(i,null);
    }
    monthlyMap.put(k,innerMap);
}

こうして初期化しておけばVisualforce側でエラー出ないと思います。
その上で希望のデータを入れましょう

入れ子のMapのデータにVisualforceからアクセスするには

上記のC1の4月のデータにアクセスしたい場合は

Visualforce
<apex:outputtext value="{!monthlyMap['C1'][4]} />

という感じで指定します。

年度の商談をSOQLで取得する場合

年度の商談をSOQLで取得
Integer thisYear = 2017;
LIST<Opportunity> thisYearOpps = LIST<Opportunity>();
thisYearOpps = [SELECT ID,CloseDate,categoryName__c FROM Opportunity WHERE FISCAL_YEAR(CloseDate) = :thisYear];

こんな感じでFISCAL_YEAR(CloseDate)を使う
categoryName__cは適当なカスタム項目です。

商談のリストに絡めた形でMapのデータを取得するには

よくやるパターンですが、例えば商談の集計結果に付随したデータみたいなのを表示したいという場合です。
上記のthisYearOppsを表示して、それに引っ掛けてmonthlyMapのデータを使ってみます

Visualforce
<apex:repeat value="{!thisYearOpps}" var="op">
<apex:outputtext value="{!monthlyMap[op.categoryName__c][month(op.CloseDate)]} />
</apex:repeat>

こんな風にします。Visualforce側で month()でDate型のデータを囲むとInteger型で月の数字を返してくれます。

一番上に書いたようなテーブルを作る場合は、LIST>みたいな感じでリストのリストにしてapex:repeatを入れ子にすれば良いでしょう。