关于Salesforce存在至于项目的选择List的取值问题
概要:
我们在做项目的时候,经常会遇到一个问题:
一个选择List字段的可选项被另一个选择List制约,这种情况如何在后台取得这两者的对应关系。
原文在这里(侵删):
Apexで連動項目の選択肢を取得する方法(改善版) - Qiita
之前第一个博文看不懂,看了第二个之后才明白大概原理。
所以才有了这篇随笔:
·Example.apxc public class Example { private static String INITIAL_VALUE = ''; // 選択リストで選択された値が格納される変数 public SomeObject objectInstance {get; set;} public List<SelectOption> DependentPickListOptions{ get{ List<SelectOption> options = new List<SelectOption>(); // 選択リストの一番上にデフォルトの選択値を設定 options.add(new SelectOption(INITIAL_VALUE, '-- なし --')); // 制御項目ctrlPicklistが選択されている時に連動項目depPicklistで選べる選択肢を取得する。 if( this.objectInstance.ctrlPicklist != null || this.objectInstance.ctrlPicklist != INITIAL_VALUE ){ List<DepPickListCtrl.TPicklistEntry> tPicklistEntries = DepPickListCtrl.GetDependentOptions('SomeObject','ctrlPicklist','depPicklist').get(this.objectInstance.ctrlPicklist); for( DepPickListCtrl.TPicklistEntry e : tPicklistEntries ){ options.add(new SelectOption(e.value, e.label)); } } return options; } } // コンストラクタ public Example(){ this.objectInstance = new SomeObject(); } }
这个部分,相信大部分人都能查看文档弄清楚。
最关键的下面这个方法(GetDependentOptions):DepPickListCtrl.apxc
/* Reference * Great thanks to Neel * http://titancronus.com/blog/2014/05/01/salesforce-acquiring-dependent-picklists-in-apex/ */ public class DepPickListCtrl { public static Map<String,List<DepPickListCtrl.TPicklistEntry>> GetDependentOptions(String pObjName, String pControllingFieldName, String pDependentFieldName){ Map<String,List<DepPickListCtrl.TPicklistEntry>> objResults = new Map<String,List<DepPickListCtrl.TPicklistEntry>>(); //get the string to sobject global map // 拿到Schema命名空间的描述
Map<String,Schema.SObjectType> objGlobalMap = Schema.getGlobalDescribe(); if (!objGlobalMap.containsKey(pObjName)) return objResults; //get the type being dealt with Schema.SObjectType pType = objGlobalMap.get(pObjName); Map<String, Schema.SObjectField> objFieldMap = pType.getDescribe().fields.getMap(); //verify field names if (!objFieldMap.containsKey(pControllingFieldName) || !objFieldMap.containsKey(pDependentFieldName)) return objResults; //get the control values // 拿到控制的选择List选项对应关系
List<Schema.PicklistEntry> ctrl_ple = objFieldMap.get(pControllingFieldName).getDescribe().getPicklistValues(); //get the dependent values // 拿到被控制的List选项对应关系
List<Schema.PicklistEntry> dep_ple = objFieldMap.get(pDependentFieldName).getDescribe().getPicklistValues(); //iterate through the values and get the ones valid for the controlling field name // 这个Validfor我实在不知道是干嘛的。官方文档上也没找打,但是这个值很重要
DepPickListCtrl.DependentValidFor dvf=new DepPickListCtrl.DependentValidFor(); //set up the results for(Integer pControllingIndex=0; pControllingIndex<ctrl_ple.size(); pControllingIndex++){ //get the pointer to the entry Schema.PicklistEntry ctrl_entry = ctrl_ple[pControllingIndex]; //get the label String pControllingLabel = ctrl_entry.getLabel(); //create the entry with the label objResults.put(pControllingLabel,new List<DepPickListCtrl.TPicklistEntry>()); } //cater for null and empty objResults.put('',new List<DepPickListCtrl.TPicklistEntry>()); objResults.put(null,new List<DepPickListCtrl.TPicklistEntry>()); //check the dependent values for(Integer pDependentIndex=0; pDependentIndex<dep_ple.size(); pDependentIndex++){ //get the pointer to the dependent index Schema.PicklistEntry dep_entry = dep_ple[pDependentIndex]; //get the valid for
// 不转换成Json,你是拿不到validfor这个值的 String pEntryStructure = JSON.serialize(dep_entry); DepPickListCtrl.TPicklistEntry objDepPLE = (DepPickListCtrl.TPicklistEntry)JSON.deserialize(pEntryStructure, DepPickListCtrl.TPicklistEntry.class); //if valid for is empty, skip if (objDepPLE.validFor==null || objDepPLE.validFor==''){ continue; } //iterate through the controlling values
// 【getControlIndexes】这个方法就是取得被控制选择List的选项的Index的方法
// 实现原理看在下面 for(Integer idx : dvf.getControlIndexes(objDepPLE.validFor)){ //get the label String pControllingValue = ctrl_ple[idx].getValue(); objResults.get(pControllingValue).add(objDepPLE); } } return objResults; } public class TPicklistEntry{ public string active {get;set;} public string defaultValue {get;set;} public string label {get;set;} public string value {get;set;} public string validFor {get;set;} public TPicklistEntry(){ } } private class DependentValidFor { private Map<String,Set<Integer>> mapValidForIndexes=new Map<String,Set<Integer>>(); public Set<Integer> getControlIndexes(String validFor){ if(mapValidForIndexes.containsKey(validFor)) return mapValidForIndexes.get(validFor); // 将validfor从Base64转化成16进制格式
// 对,也就是说,validfor是Base64格式的数据
// 而官方只提供了转化成16进制格式的方法(convertToHex),这样才将validfor变为可读数据
String hex=EncodingUtil.convertToHex(EncodingUtil.base64Decode(validFor)); Set<Integer> result=new Set<Integer>(); // 循环遍历16进制数的每一位
for(Integer i=0; i<hex.length(); i++){ String b=hex.substring(i, i+1); Integer off=i*4;
// 每一位都当成二进制数据 switch on b { //0123(index) when '0'{ //0000 }
// 第一次循环时i=0
// 当0010的时候,意味着被控制选择List的选项的Index2的选项是可选的 // 当0100的时候,意味着被控制选择List的选项的Index3的选项是可选的
// 。。。。
// 也就是说决定那个Index的选项可选不是看值的大小,
// 而是看值的位置,1处在那个位置上,index几就是可选项。
// 因为每一个16进制数可以表示n~n+4(index),
// 所以当i+1时,index就是从n+4开始的,
// 例子: i=0时,“f” → 0,1,2,3
// 例子: i=1时, “f” → 4,5,6,7
// 所以off每次都要*4
when '1'{ //0001 result.add(off+3); }
when '2'{ //0010 result.add(off+2); } when '3'{ //0011 result.add(off+2); result.add(off+3); } when '4'{ //0100 result.add(off+1); } when '5'{ //0101 result.add(off+1); result.add(off+3); } when '6'{ //0110 result.add(off+1); result.add(off+2); } when '7'{ //0111 result.add(off+1); result.add(off+2); result.add(off+3); } when '8'{ //1000 result.add(off+0); } when '9'{ //1001 result.add(off+0); result.add(off+3); } when 'a'{ //1010 result.add(off+0); result.add(off+2); } when 'b'{ //1011 result.add(off+0); result.add(off+2); result.add(off+3); } when 'c'{ //1100 result.add(off+0); result.add(off+1); } when 'd'{ //1101 result.add(off+0); result.add(off+1); result.add(off+3); } when 'e'{ //1110 result.add(off+0); result.add(off+1); result.add(off+2); } when 'f'{ //1111 result.add(off+0); result.add(off+1); result.add(off+2); result.add(off+3); } } } mapValidForIndexes.put(validFor,result); return result; } } }
DepPickListCtrl.apxc
/* Reference
* Great thanks to Neel
* http://titancronus.com/blog/2014/05/01/salesforce-acquiring-dependent-picklists-in-apex/
*/
public class DepPickListCtrl {
public static Map<String,List<DepPickListCtrl.TPicklistEntry>> GetDependentOptions(String pObjName, String pControllingFieldName, String pDependentFieldName){
Map<String,List<DepPickListCtrl.TPicklistEntry>> objResults = new Map<String,List<DepPickListCtrl.TPicklistEntry>>();
//get the string to sobject global map
Map<String,Schema.SObjectType> objGlobalMap = Schema.getGlobalDescribe();
if (!objGlobalMap.containsKey(pObjName))
return objResults;
//get the type being dealt with
Schema.SObjectType pType = objGlobalMap.get(pObjName);
Map<String, Schema.SObjectField> objFieldMap = pType.getDescribe().fields.getMap();
//verify field names
if (!objFieldMap.containsKey(pControllingFieldName) || !objFieldMap.containsKey(pDependentFieldName))
return objResults;
//get the control values
List<Schema.PicklistEntry> ctrl_ple = objFieldMap.get(pControllingFieldName).getDescribe().getPicklistValues();
//get the dependent values
List<Schema.PicklistEntry> dep_ple = objFieldMap.get(pDependentFieldName).getDescribe().getPicklistValues();
//iterate through the values and get the ones valid for the controlling field name
DepPickListCtrl.DependentValidFor dvf=new DepPickListCtrl.DependentValidFor();
//set up the results
for(Integer pControllingIndex=0; pControllingIndex<ctrl_ple.size(); pControllingIndex++){
//get the pointer to the entry
Schema.PicklistEntry ctrl_entry = ctrl_ple[pControllingIndex];
//get the label
String pControllingLabel = ctrl_entry.getLabel();
//create the entry with the label
objResults.put(pControllingLabel,new List<DepPickListCtrl.TPicklistEntry>());
}
//cater for null and empty
objResults.put('',new List<DepPickListCtrl.TPicklistEntry>());
objResults.put(null,new List<DepPickListCtrl.TPicklistEntry>());
//check the dependent values
for(Integer pDependentIndex=0; pDependentIndex<dep_ple.size(); pDependentIndex++){
//get the pointer to the dependent index
Schema.PicklistEntry dep_entry = dep_ple[pDependentIndex];
//get the valid for
String pEntryStructure = JSON.serialize(dep_entry);
DepPickListCtrl.TPicklistEntry objDepPLE = (DepPickListCtrl.TPicklistEntry)JSON.deserialize(pEntryStructure, DepPickListCtrl.TPicklistEntry.class);
//if valid for is empty, skip
if (objDepPLE.validFor==null || objDepPLE.validFor==''){
continue;
}
//iterate through the controlling values
for(Integer idx : dvf.getControlIndexes(objDepPLE.validFor)){
//get the label
String pControllingValue = ctrl_ple[idx].getValue();
objResults.get(pControllingValue).add(objDepPLE);
}
}
return objResults;
}
public class TPicklistEntry{
public string active {get;set;}
public string defaultValue {get;set;}
public string label {get;set;}
public string value {get;set;}
public string validFor {get;set;}
public TPicklistEntry(){
}
}
private class DependentValidFor {
private Map<String,Set<Integer>> mapValidForIndexes=new Map<String,Set<Integer>>();
public Set<Integer> getControlIndexes(String validFor){
if(mapValidForIndexes.containsKey(validFor))
return mapValidForIndexes.get(validFor);
String hex=EncodingUtil.convertToHex(EncodingUtil.base64Decode(validFor));
Set<Integer> result=new Set<Integer>();
for(Integer i=0; i<hex.length(); i++){
String b=hex.substring(i, i+1);
Integer off=i*4;
switch on b { //0123(index)
when '0'{ //0000
}
when '1'{ //0001
result.add(off+3);
}
when '2'{ //0010
result.add(off+2);
}
when '3'{ //0011
result.add(off+2);
result.add(off+3);
}
when '4'{ //0100
result.add(off+1);
}
when '5'{ //0101
result.add(off+1);
result.add(off+3);
}
when '6'{ //0110
result.add(off+1);
result.add(off+2);
}
when '7'{ //0111
result.add(off+1);
result.add(off+2);
result.add(off+3);
}
when '8'{ //1000
result.add(off+0);
}
when '9'{ //1001
result.add(off+0);
result.add(off+3);
}
when 'a'{ //1010
result.add(off+0);
result.add(off+2);
}
when 'b'{ //1011
result.add(off+0);
result.add(off+2);
result.add(off+3);
}
when 'c'{ //1100
result.add(off+0);
result.add(off+1);
}
when 'd'{ //1101
result.add(off+0);
result.add(off+1);
result.add(off+3);
}
when 'e'{ //1110
result.add(off+0);
result.add(off+1);
result.add(off+2);
}
when 'f'{ //1111
result.add(off+0);
result.add(off+1);
result.add(off+2);
result.add(off+3);
}
}
}
mapValidForIndexes.put(validFor,result);
return result;
}
}
}