Регистрация  |  Вход

Dependent picklist в Apex

Как получить значения dependent picklist в Apex?

Желательно в такой форме: Map<ControllingFieldValue, List<DependentFieldValue>>

Как получить значения dependent picklist в Apex?

Желательно в такой форме: Map<ControllingFieldValue, List<DependentFieldValue>>
[url=http://titancronus.com/blog/2014/05/01/salesforce-acquiring-dependent-picklists-in-apex/]Salesforce: Acquiring Dependent Picklists in Apex[/url]

Я это решениеи использовал, но сегодня столкнулся с тем, что оно не всегда корректно срабатывает.

В моём случае есть 3 пиклиста, два из которых зависимы: PickList1 -> PickList2 -> PickList3. PickList2 - работает, а PickList3 работает неправильно - в случае когда пиклист должен быть пустым в нём появляются значения, которые не были указаны в маппинге.

Кто-нибудь сталкивался с похожим поведением?

Я это решениеи использовал, но сегодня столкнулся с тем, что оно не всегда корректно срабатывает. 

В моём случае есть 3 пиклиста, два из которых зависимы: PickList1 -> PickList2 -> PickList3. PickList2 - работает, а PickList3 работает неправильно - в случае когда пиклист должен быть пустым в нём появляются значения, которые не были указаны в маппинге. 

Кто-нибудь сталкивался с похожим поведением?

Gres
Salesforce: Acquiring Dependent Picklists in Apex

Попробовал решение по ссылке
получаю вот такую ошибку

Нет возможности понять этот магический метод в деталях, может кто сталкивался и знает решение?

[quote="Gres"]Salesforce: Acquiring Dependent Picklists in Apex[/quote]
Попробовал решение по ссылке
получаю вот такую ошибку

[img]https://cdn.pbrd.co/images/fKLXfyat2.png[/img]

Нет возможности понять этот магический метод в деталях, может кто сталкивался и знает решение?

глянь комменты в блоге, там добавляют символы в мапу. там вроде недавно ещё в комментах новую версию метода сделали, оптимизировали

глянь комменты в блоге, там добавляют символы в мапу. там вроде недавно ещё в комментах новую версию метода сделали, оптимизировали

Dmitry Lisovsky
глянь комменты в блоге

Дима, спасибо, выручил!!!

добавил вот эти 2 строчки в метод loadCharCodes

Base64CharCodes.put('+', 62);
Base64CharCodes.put('/', 63);

У меня такое предположение что оригинальный метод не переваривал значения из пиклиста с пробелом.

[quote="Dmitry Lisovsky"]глянь комменты в блоге[/quote]

Дима, спасибо, выручил!!!

добавил вот эти 2 строчки в метод loadCharCodes
[code]
Base64CharCodes.put('+', 62);
Base64CharCodes.put('/', 63);
[/code]

У меня такое предположение что оригинальный метод не переваривал значения из пиклиста с пробелом.

Да, в комментах там все есть. Надо на GitHub выложить рабочую версию, что б не клепать ее каждый раз из кусков.

Да, в комментах там все есть. Надо на GitHub выложить рабочую версию, что б не клепать ее каждый раз из кусков.

По ссылке, в моем случае, код не всегда возвращал корректные значения пиклистов, записывал dependant значения пиклистов к неправильным controlling. Этот код (взятый из комментария по ссылке http://titancronus.com/blog/2014/07/03/acquiring-dependent-picklists-in-apex-contd/) возвращает правильные значение:

//----------------------------------- GETTING DEPENDANT PICKLISTS -----------------------------------//
//copy-pasted from http://titancronus.com/blog/2014/07/03/acquiring-dependent-picklists-in-apex-contd/ from Paul N's comment.
// **********************************************************************************************************************************
// ********** GetDependentOptions ***************************************************************************************************
// **********************************************************************************************************************************
// Map<String,List<String>> GetDependentOptions (String pObjName, String pControllingFieldName, String pDependentFieldName)
// Returns: Map of "pControllingFieldName" picklist values and their corresponding "pDependentFieldName" dependent option values.
// **********************************************************************************************************************************

/*
* @Summary: Entity to represent a json version of a picklist entry
* so that the validFor property becomes exposed
*/
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() {

}
}


// Converts a base64 string into a list of integers representing the encoded bytes
public static List<Integer> B64ToBytes (String sIn) {
Map<Integer,Integer> base64 = new Map<Integer,Integer>{65=>0,66=>1,67=>2,68=>3,69=>4,70=>5,71=>6,72=>7,73=>8,74=>9,75=>10,76=>11,77=>12,78=>13,79=>14,80=>15,81=>16,82=>17,83=>18,84=>19,85=>20,86=>21,87=>22,88=>23,89=>24,90=>25
,97=>26,98=>27,99=>28,100=>29,101=>30,102=>31,103=>32,104=>33,105=>34,106=>35,107=>36,108=>37,109=>38,110=>39,111=>40,112=>41,113=>42,114=>43,115=>44,116=>45,117=>46,118=>47,119=>48,120=>49,121=>50,122=>51
,48=>52,49=>53,50=>54,51=>55,52=>56,53=>57,54=>58,55=>59,56=>60,57=>61,43=>62,47=>63};

List<Integer> lstOut = new List<Integer>();
if ( sIn == null || sIn == '' ) return lstOut;

sIn += '='.repeat( 4 - Math.mod( sIn.length(), 4) );

for ( Integer idx=0; idx < sIn.length(); idx += 4 ) {
if ( base64.get(sIn.charAt(idx+1)) != null ) lstOut.add( (base64.get(sIn.charAt(idx)) << 2) | (base64.get(sIn.charAt(idx+1)) >>> 4) );
if ( base64.get(sIn.charAt(idx+2)) != null ) lstOut.add( ((base64.get(sIn.charAt(idx+1)) & 15)<<4) | (base64.get(sIn.charAt(idx+2)) >>> 2) );
if ( base64.get(sIn.charAt(idx+3)) != null ) lstOut.add( ((base64.get(sIn.charAt(idx+2)) & 3)<<6) | base64.get(sIn.charAt(idx+3)) );
}

//System.Debug('B64ToBytes: [' + sIn + '] = ' + lstOut);
return lstOut;
}//B64ToBytes
public static List<Integer> BlobToBytes (Blob input) {
return B64ToBytes( EncodingUtil.base64Encode(input) );
}//BlobToBytes

// Converts a base64 string into a list of integers indicating at which position the bits are on
public static List<Integer> cnvBits (String b64Str) {
List<Integer> lstOut = new List<Integer>();
if ( b64Str == null || b64Str == '' ) return lstOut;

List<Integer> lstBytes = B64ToBytes(b64Str);

Integer i, b, v;
for ( i = 0; i < lstBytes.size(); i++ ) {
v = lstBytes[i];
//System.debug ( 'i['+i+'] v['+v+']' );
for ( b = 1; b <= 8; b++ ) {
//System.debug ( 'i['+i+'] b['+b+'] v['+v+'] = ['+(v & 128)+']' );
if ( ( v & 128 ) == 128 ) lstOut.add( (i*8) + b );
v <<= 1;
}
}

//System.Debug('cnvBits: [' + b64Str + '] = ' + lstOut);
return lstOut;
}//cnvBits

public static Map<String,List<String>> GetDependentOptions(String pObjName, String pControllingFieldName, String pDependentFieldName) {
Map<String,List<String>> mapResults = new Map<String,List<String>>();

//verify/get object schema
Schema.SObjectType pType = Schema.getGlobalDescribe().get(pObjName);
if ( pType == null ) return mapResults;
Map<String, Schema.SObjectField> objFieldMap = pType.getDescribe().fields.getMap();

//verify field names
if (!objFieldMap.containsKey(pControllingFieldName) || !objFieldMap.containsKey(pDependentFieldName)) return mapResults;

//get the control & dependent values
List<Schema.PicklistEntry> ctrl_ple = objFieldMap.get(pControllingFieldName).getDescribe().getPicklistValues();
List<Schema.PicklistEntry> dep_ple = objFieldMap.get(pDependentFieldName).getDescribe().getPicklistValues();

//clear heap
objFieldMap = null;

//initialize results mapping
for(Integer pControllingIndex=0; pControllingIndex<ctrl_ple.size(); pControllingIndex++){
mapResults.put( ctrl_ple[pControllingIndex].getLabel(), new List<String>());
}
//cater for null and empty
//mapResults.put('', new List<String>());
//mapResults.put(null, new List<String>());

//serialize dep entries
List<SFDescribeHelper.TPicklistEntry> objDS_Entries = new List<SFDescribeHelper.TPicklistEntry>();
objDS_Entries = (List<SFDescribeHelper.TPicklistEntry>)JSON.deserialize(JSON.serialize(dep_ple), List<SFDescribeHelper.TPicklistEntry>.class);

List<Integer> validIndexes;
for (SFDescribeHelper.TPicklistEntry objDepPLE : objDS_Entries){

validIndexes = cnvBits(objDepPLE.validFor);
//System.Debug('cnvBits: [' + objDepPLE.label + '] = ' + validIndexes);

for (Integer validIndex : validIndexes){
mapResults.get( ctrl_ple[validIndex-1].getLabel() ).add( objDepPLE.label );
}
}

//clear heap
objDS_Entries = null;

return mapResults;
}

//----------------------------------- OVER GETTING DEPENDANT PICKLISTS -----------------------------------//

По ссылке, в моем случае, код не всегда возвращал корректные значения пиклистов, записывал dependant значения пиклистов к неправильным controlling. Этот код (взятый из комментария по ссылке http://titancronus.com/blog/2014/07/03/acquiring-dependent-picklists-in-apex-contd/) возвращает правильные значение:
[code]
//----------------------------------- GETTING DEPENDANT PICKLISTS -----------------------------------//
    //copy-pasted from http://titancronus.com/blog/2014/07/03/acquiring-dependent-picklists-in-apex-contd/ from Paul N's comment.
    // **********************************************************************************************************************************
    // ********** GetDependentOptions ***************************************************************************************************
    // **********************************************************************************************************************************
    // Map<String,List<String>> GetDependentOptions (String pObjName, String pControllingFieldName, String pDependentFieldName)
    // Returns: Map of "pControllingFieldName" picklist values and their corresponding "pDependentFieldName" dependent option values.
    // **********************************************************************************************************************************

    /*
     * @Summary: Entity to represent a json version of a picklist entry
     * so that the validFor property becomes exposed
     */
    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() {

        }
    }


    // Converts a base64 string into a list of integers representing the encoded bytes
    public static List<Integer> B64ToBytes (String sIn) {
        Map<Integer,Integer> base64 = new Map<Integer,Integer>{65=>0,66=>1,67=>2,68=>3,69=>4,70=>5,71=>6,72=>7,73=>8,74=>9,75=>10,76=>11,77=>12,78=>13,79=>14,80=>15,81=>16,82=>17,83=>18,84=>19,85=>20,86=>21,87=>22,88=>23,89=>24,90=>25
                                                               ,97=>26,98=>27,99=>28,100=>29,101=>30,102=>31,103=>32,104=>33,105=>34,106=>35,107=>36,108=>37,109=>38,110=>39,111=>40,112=>41,113=>42,114=>43,115=>44,116=>45,117=>46,118=>47,119=>48,120=>49,121=>50,122=>51
                                                               ,48=>52,49=>53,50=>54,51=>55,52=>56,53=>57,54=>58,55=>59,56=>60,57=>61,43=>62,47=>63};

        List<Integer> lstOut = new List<Integer>();
        if ( sIn == null || sIn == '' ) return lstOut;
        
        sIn += '='.repeat( 4 - Math.mod( sIn.length(), 4) );

        for ( Integer idx=0; idx < sIn.length(); idx += 4 ) {
            if ( base64.get(sIn.charAt(idx+1)) != null ) lstOut.add( (base64.get(sIn.charAt(idx)) << 2) | (base64.get(sIn.charAt(idx+1)) >>> 4) );
            if ( base64.get(sIn.charAt(idx+2)) != null ) lstOut.add( ((base64.get(sIn.charAt(idx+1)) & 15)<<4) | (base64.get(sIn.charAt(idx+2)) >>> 2) );
            if ( base64.get(sIn.charAt(idx+3)) != null ) lstOut.add( ((base64.get(sIn.charAt(idx+2)) & 3)<<6) | base64.get(sIn.charAt(idx+3)) );
        }

        //System.Debug('B64ToBytes: [' + sIn + '] = ' + lstOut);
        return lstOut;
    }//B64ToBytes
    public static List<Integer> BlobToBytes (Blob input) {
        return B64ToBytes( EncodingUtil.base64Encode(input) );
    }//BlobToBytes

    // Converts a base64 string into a list of integers indicating at which position the bits are on
    public static List<Integer> cnvBits (String b64Str) {
        List<Integer> lstOut = new List<Integer>();
        if ( b64Str == null || b64Str == '' ) return lstOut;

        List<Integer> lstBytes = B64ToBytes(b64Str);

        Integer i, b, v;
        for ( i = 0; i < lstBytes.size(); i++ ) {
            v = lstBytes[i];
            //System.debug ( 'i['+i+'] v['+v+']' );
            for ( b = 1; b <= 8; b++ ) {
                //System.debug ( 'i['+i+'] b['+b+'] v['+v+'] = ['+(v & 128)+']' );
                if ( ( v & 128 ) == 128 ) lstOut.add( (i*8) + b );
                v <<= 1;
            }
        }

        //System.Debug('cnvBits: [' + b64Str + '] = ' + lstOut);
        return lstOut;
    }//cnvBits
     
    public static Map<String,List<String>> GetDependentOptions(String pObjName, String pControllingFieldName, String pDependentFieldName) {
        Map<String,List<String>> mapResults = new Map<String,List<String>>();

        //verify/get object schema
        Schema.SObjectType pType = Schema.getGlobalDescribe().get(pObjName);
        if ( pType == null ) return mapResults;
        Map<String, Schema.SObjectField> objFieldMap = pType.getDescribe().fields.getMap();

        //verify field names
        if (!objFieldMap.containsKey(pControllingFieldName) || !objFieldMap.containsKey(pDependentFieldName)) return mapResults;     

        //get the control & dependent values   
        List<Schema.PicklistEntry> ctrl_ple = objFieldMap.get(pControllingFieldName).getDescribe().getPicklistValues();
        List<Schema.PicklistEntry> dep_ple = objFieldMap.get(pDependentFieldName).getDescribe().getPicklistValues();

        //clear heap
        objFieldMap = null;

        //initialize results mapping
        for(Integer pControllingIndex=0; pControllingIndex<ctrl_ple.size(); pControllingIndex++){           
            mapResults.put( ctrl_ple[pControllingIndex].getLabel(), new List<String>());
        }
        //cater for null and empty
        //mapResults.put('', new List<String>());
        //mapResults.put(null, new List<String>());

        //serialize dep entries        
        List<SFDescribeHelper.TPicklistEntry> objDS_Entries = new List<SFDescribeHelper.TPicklistEntry>();
        objDS_Entries = (List<SFDescribeHelper.TPicklistEntry>)JSON.deserialize(JSON.serialize(dep_ple), List<SFDescribeHelper.TPicklistEntry>.class);

        List<Integer> validIndexes;
        for (SFDescribeHelper.TPicklistEntry objDepPLE : objDS_Entries){

            validIndexes = cnvBits(objDepPLE.validFor);
            //System.Debug('cnvBits: [' + objDepPLE.label + '] = ' + validIndexes);

            for (Integer validIndex : validIndexes){                
                mapResults.get( ctrl_ple[validIndex-1].getLabel() ).add( objDepPLE.label );
            }
        }

        //clear heap
        objDS_Entries = null;

        return mapResults;
    }

    //----------------------------------- OVER GETTING DEPENDANT PICKLISTS -----------------------------------//
[/code]

Да, кстати, есть такое - оригинал из статьи нерабочий, хотя повсеместно используется в проектах.
Странно что его еще не поправили. Там в комментах к статье где-то пробегала ссылка на исходники уже работающие правильно. Не могу сравнить с тем что приведено выше.

EvAzi
Этот код (взятый из комментария по ссылке http://titancronus.com/blog/2014/07/03/acquiring-dependent-picklists-in-apex-contd/) возвращает правильные значение:

Можешь перенести его куда-нибудь в github и заменить на ссылку? А то что-то на форуме исходники хреново отображаются.

Да, кстати, есть такое - оригинал из статьи нерабочий, хотя повсеместно используется в проектах.
Странно что его еще не поправили. Там в комментах к статье где-то пробегала ссылка на исходники уже работающие правильно. Не могу сравнить с тем что приведено выше.

[quote="EvAzi"]Этот код (взятый из комментария по ссылке http://titancronus.com/blog/2014/07/03/acquiring-dependent-picklists-in-apex-contd/) возвращает правильные значение: [/quote]
Можешь перенести его куда-нибудь в github и заменить на ссылку? А то что-то на форуме исходники хреново отображаются.

Сам использовал эту же наработку и исправления в комментах. Где-то у меня в проектах есть рабочий вариант и тоже хотел выложить. Но, как обычно, нет времени.

Сам использовал эту же наработку и исправления в комментах. Где-то у меня в проектах есть рабочий вариант и тоже хотел выложить. Но, как обычно, нет времени.

В том то и дело что это не исправления в комментах. А был метод альтернативный, там немного по другому рассчитывается битовые сдвиги и нет этого страшного маппинга ASCII на коды.

В том то и дело что это не исправления в комментах. А был метод альтернативный, там немного по другому рассчитывается битовые сдвиги и нет этого страшного маппинга ASCII на коды.

Dmitry Shnyrev
Можешь перенести его куда-нибудь в github и заменить на ссылку? А то что-то на форуме исходники хреново отображаются.

Если только pastebin: https://pastebin.com/KFKASKva

[quote="Dmitry Shnyrev"]Можешь перенести его куда-нибудь в github и заменить на ссылку? А то что-то на форуме исходники хреново отображаются.[/quote]
Если только pastebin: https://pastebin.com/KFKASKva