注:本篇解決方案內容實現轉自:http://mysalesforceescapade.blogspot.com/2015/03/getting-dependent-picklist-values-from.html
群里面有個小伙伴問了一個關於兩個有Dependence關系的Picklist字段如何在Apex中通過control字段的值獲取到Dependence字段的值,針對Salesforce配置來說,我們很好配置出兩個Dependence字段的關系,通過點擊設置一下include關系即可。如下圖,我們在Goods__c自定義表中新建了兩個Picklist類型字段,並且設置了依賴關系,這個在配置中清晰可見,如何在代碼中獲取呢?

首先我們最先想到的肯定是通過metadata,查一下Schema命名空間下的類得方法有沒有直接可以搞定需求的,針對Picklist值,通常處理的類為Schema.PicklistEntry以及Schema.DescribeFieldResult這兩個類,然而這兩個類的API中並沒有直接可以搞定需求的,只能判斷出當前的字段是否為空值字段等信息。既然標准的API沒有提供,那么就得想辦法搞定了。我的第一次想法是這樣的,盡管這種方式最終確認是失敗的。
一.將兩個依賴字段放置在頁面中,Util方法讀取頁面中指定元素從而獲取Control字段的某一個值情況下Dependence的值集合。(此方法已確認失敗)
salesforce 零基礎學習(六十二)獲取sObject中類型為Picklist的field values(含record type) 寫過關於讀取中間頁面獲取含Record Type的Picklist field Values,是不是也可以將中間頁面寫兩個apex:inputField設置級聯關系,通過參數將需要讀取的內容獲取出來,從而實現需求?
1.PicklistParserController作為中間頁的Controller,獲取參數信息,通過參數對數據進行初始化處理。
public without sharing class PicklistParserController { public Sobject sobj {get;set;} public String picklistFieldName {get;set;} public String dependentPicklistListFieldName { get; set; } public String picklistFieldValue { get; set; } public PicklistParserController() { Map<String, String> requestMap = ApexPages.currentPage().getParameters(); String sobjId = requestMap.get('id'); String recordTypeId = requestMap.get('recordTypeId'); String sobjectTypeName = requestMap.get('sobjectType'); this.pickListFieldName = requestMap.get('picklistFieldName'); this.dependentPicklistListFieldName = requestMap.get('dependentPicklistListFieldName'); this.picklistFieldValue = requestMap.get('picklistFieldValue'); Schema.SobjectType sobjectType = null; if (sobjectTypeName != null && sobjectTypeName.trim().length() > 0) { sobjectType = Schema.getGlobalDescribe().get(sobjectTypeName); sobj = sobjectType.newSobject(); sobj.put('RecordTypeId', recordTypeid); if(picklistFieldValue != null) { sobj.put(pickListFieldName,picklistFieldValue); } } else if (sobjId != null && sobjId.trim().length() > 0) { // find the so for (SobjectType sobjType : Schema.getGlobalDescribe().values()){ String sobjPrefix = sobjType.getDescribe().getKeyPrefix(); if (sobjPrefix == null) continue; if (sobjId.toLowerCase().startsWith(sobjPrefix.toLowerCase())) { sobjectType = sobjType; break; } } sobj = Database.query ('SELECT ' + pickListFieldName + ',' + dependentPicklistListFieldName + ' FROM ' + sobjectType + ' WHERE ID =:sobjId'); } System.debug(LoggingLevel.INFO, '*** sobj: ' + JSON.serialize(sobj)); } }
2.PicklistParser.page 顯示兩個依賴關系字段
<apex:page controller="PicklistParserController" contentType="application/xml" showHeader="false" sidebar="false" standardStylesheets="false" language="en_US"> <apex:form > <apex:inputField value="{!sobj[pickListFieldName]}" /> <apex:inputField value="{!sobj[dependentPicklistListFieldName]}" id="dependentPicklistListFieldName" required="true"/> </apex:form> </apex:page>
3.PicklistParserUtil:此方法用於查看解析中間頁面的結果展示
public with sharing class PicklistParserUtil {public static String parseOptions(Map<String, String> params) { Pagereference pr = Page.PicklistParser; // to handle development mode, if ON pr.getParameters().put('core.apexpages.devmode.url', '1'); System.debug(LoggingLevel.INFO, '*** params: ' + JSON.serialize(params)); for (String key : params.keySet()) { pr.getParameters().put(key, params.get(key)); } String xmlContent = pr.getContent().toString(); return xmlContent; } }
中間頁面效果展示如下: 通過下圖可以看到,當控制字段選擇了某個以后,級聯字段展示了其對應的依賴字段值。

測試代碼如下:
Map<string,String> m = new Map<string,String>(); m.put('sobjectType', 'Goods__c'); m.put('picklistFieldName','TestP1__c'); m.put('dependentPicklistListFieldName','TestP2__c'); m.put('picklistFieldValue', '測試1'); System.debug(LoggingLevel.INFO, '*** : ' + PicklistParserUtil.parseOptions(m));
但是當解析這個輸出結果時,發現輸出的內容和設想的不太一樣。原來設想的內容是解析的結果會有兩個select option 區域,兩個區域分別展示對應的value,后期只需要針對獲取指定select下所有的option即可。然而實際的部分結果展示如下:
<select id="j_id0:j_id1:j_id2" name="j_id0:j_id1:j_id2"> <option value="">--None--</option> <option value="T1" selected="selected">T1</option> <option value="T2">T2</option> <option value="T3">T3</option> <option value="T4">T4</option> <option value="測試1">測試1</option> <option value="測試2">測試2</option> </select> <div class="requiredInput"><div class="requiredBlock"></div><span> <select id="j_id0:j_id1:dependentPicklistListFieldName" name="j_id0:j_id1:dependentPicklistListFieldName"> <option value="" selected="true">--None--</option> </select></span></div><div id="j_id0:j_id1:j_id3"> <script>window.pl = window.pl || {}; pl.map_00N0I00000JsNOk_01228000000U1u0={'T4':'DAAA','測試2':'IQAA','測試1':'ggAA','T1':'wAAA','T2':'MAAA','T3':'GAAA'}; pl.vals_00N0I00000JsNOk_01228000000U1u0=['TestS1','TestS1','TestS2','TestS2','TestS3','TestS3','TestS4','TestS4','TestS5','TestS5','TestS6','TestS6','測試S1','測試S1','測試S2','測試S2']; pl.noneLabel="--None--"; pl.naLabel="\*\*Not Applicable\*\*"; pl.selectedLabel="Chosen"; pl.availableLabel="Available"; new picklist('j_id0:j_id1:dependentPicklistListFieldName','00N0I00000JsNOk_01228000000U1u0','00N0I00000JsNOk_01228000000U1u0','j_id0:j_id1:j_id2',['',''],' id=\"j_id0:j_id1:dependentPicklistListFieldName\" name=\"j_id0:j_id1:dependentPicklistListFieldName\"',false,true); </script> </div>
也就是說每次點擊父的值情況下,js會動態通過當前的父的值獲取子內容,通過解析頁面方式無法獲取其真實的依賴關系,所以此種方式棄用了。
二.使用PicklistEntry方式(正確方式)
此部分內容參考內容:
http://mysalesforceescapade.blogspot.com/2015/03/getting-dependent-picklist-values-from.html
兩個Picklist的Dependence肯定是以某種方式存儲在MetaData中的,即使官方的API沒有提供可以直接調用的方法獲取到Dependence關系,肯定某個屬性中也存儲了這種關系。
通過第一個鏈接可以發現,PicklistEntry的validFor屬性中存儲了兩者的關系,對於PicklistEntry來說,每一個Denpendence Picklist 的Value代表一個PicklistEntry。
每一個validFor屬性存儲了一組的Bits,每個bit對應着一個Control Field Picklist Value。官方的描述為 A set of bits where each bit indicates a controlling value for which this PicklistEntry is valid。validFor在java中返回類型為byte[],因為salesforce中沒有byte這個基本類型,我們可以通過byte的性質,或者直接看byte在java中的定義,模擬出byte的Wrapper使用,官方給了一個java版的獲取方式,下面的鏈接為國外一個大牛寫的demo可以獲取到Picklist中的Dependence關系,內容和java版的獲取方式相差不大,區別為自己封裝了一個Byte類。
代碼測試:
System.debug(LoggingLevel.INFO, '*** : ' + JSON.serialize(new PicklistFieldController().getDependentOptionsImpl('Goods__c','TestP1__c','TestP2__c')));
結果展示:

總結:在Apex Class中獲取Picklist間的級聯關系,主要是通過PicklistEntry中的隱藏屬性validFor獲取其中的關系,並對返回的byte[]數組進行解析找到其對應的control的關系。篇中有錯誤地方歡迎指出,不懂的歡迎留言。
