+ Start a Discussion
DCSDCS 

Custom object to hold settings - Prevent hardcoding in Apex code

I have a custom object called 'Sample Request' which has look up  relationship to lead object and contact object. There are many record types for Contact and also for Lead as my company has business in different regions. Due to the same reason there are different page layouts and record types for 'Sample Request' object also.

 

 

 

To make it simple for Ex: say there are

2 rec types and page layouts for Contact - C1 and C2 and there are

2 rec types and page layouts for Lead  - L1 and L2 and there are

4 rec types and page layouts for Sample Request - R1, R2, R3, R4

 

I have created a custom button (VF page and controller) called 'Create sample Request' in Lead and Contact page that takes user to the appropriate 'Sample Request' page depending on the originating record type of contact or Lead. 

 

The apex controller code checks various record types as below

if the record type is C1 forward the user to page with Rec type as R1

if the record type is C2 forward the user to page with Rec type as R2

if the record type is L1 forward the user to page with Rec type as R3

if the record type is L2 forward the user to page with Rec type as R4

 

When there is a new rec type added for a different business unit, changes are needed in the code to handle the new Rec Type. This needs code deployment to production apart from config changes.  

 

I am looking into creating a custom object that will hold setting like this that can be used by the Apex controller to forward user to the correct page layout. In this case it is a simple mapping of Rec type to Rec type in the custom object. This will make the code generic enough, prevent the hardcoding of record types in the code and reduce maintenance with future config changes. When there is a new record type, a new record need to be added in the custom object and we are good to go.  

 

I looked into using custom settings, but I am not able to figure out if that can be used for something like this. I am sure this hardcoding in code is something that everyone runs into at one point or other. I would like to know how others are handling scenarios like this. Any suggestions/comments would be very helpful.

 

Thanks!

 

 

 

 

 

 

 

Message Edited by DCS on 04-01-2010 06:18 AM
Best Answer chosen by Admin (Salesforce Developers) 
CaptainObviousCaptainObvious

After some playing around with Custom Settings, I think it may be possible to implement your idea...

 

I created a Custom Setting called "RecordTypeForwarding"
    Label RecordTypeForwarding
    Object Name RecordTypeForwarding
    Visibility Public
    Setting Type List

 

Next, I created 2 Custom Fields (these would be populated record type labels, so I set the data type to Text).

    Field Label Origin, Data Type Text(255)
    Field Label Destination, Data Type Text(255)

 

For each data set, I picked a name for the set and an existing record type label for the Origin and Destination.
(For my test I used a Contact record type label as the origin, and Account record type label as the destination)

 

    For the first data set:
         Name Set1
         Origin ContactRecordTypeLabel1
         Destination AccountRecordTypeLabel1
    For the second data set:
         Name Set2
         Origin ContactRecordTypeLabel2
         Destination AccountRecordTypeLabel2


Next, I created a global utility class which I could call from Apex:

 

global class util {    

    //Retrieve record type ids    
    public static Map<String,Id> getRecordTypeMap(String objType) {        
        Map<String,Id> recTypes = new Map<String,Id>();        
        for(RecordType recType:Database.query('SELECT id, name FROM RecordType WHERE sObjectType =\'' + objType + '\'')) {
            recTypes.put(recType.Name, recType.Id);
        }
        return recTypes;
    }

    //Retrieve record type labels    
    public static Map<Id,String> getRecordTypeLabelMap(String objType) {        
        Map<Id,String> rTypes = new Map<Id,String>();        
        for(RecordType recType:Database.query('SELECT id, name FROM RecordType WHERE sObjectType =\'' + objType + '\'')) {
            rTypes.put(recType.Id,recType.Name);
        }
        return rTypes;
    }

    //Retrieve all data sets from RecordTypeForwarding Custom Setting
    public static List<RecordTypeForwarding__c> getAllRecordTypeForwarding() {
    List<RecordTypeForwarding__c> allSets = RecordTypeForwarding__c.getall().values();
        return allSets;
    }

    //Retrieve a specific data set from RecordTypeForwarding Custom Setting
    public static RecordTypeForwarding__c getRecordTypeForwarding(String dataset) {
        RecordTypeForwarding__c dSet = RecordTypeForwarding__c.getValues(dataset);
        return dSet;
    }

}

How to use this:

 

//First determine the 'origin' RecordtypeId (you would set this in your controller)
Id rtype;

//Next, get the RecordType Label (we need this to search for the data set)
//Remember, in my example, all Origin Id's are form the Contact object
Map<Id,String> conRecordTypeLabels = util.getRecordTypeLabelMap('Contact');
String originRTypeLabel = conRecordTypeLabels.get(rtype);

//Using the RecordType Label we found, determine which Data Set to use
String dataSetName;
List<RecordTypeForwarding__c> dataSets = util.getAllRecordTypeForwarding();
for(integer i=0;i<dataSets.size();i++) { 
    if (dataSets[i].Origin__c == originRTypeLabel) {
        dataSetName = dataSets[i].Name;
        break;
    }
}

//Get the specific data set from the Custom Setting
RecordTypeForwarding__c dataSet = util.getRecordTypeForwarding(dataSetName);

//Create a map of record type ids for the Origin and Destination objects
Map<String,Id> conRecordTypeIds = util.getRecordTypeMap('Contact');
Map<String,Id> acRecordTypes = util.getRecordTypeMap('Account');

//Now assign the Origin and destination IDs:
Id OriginId = conRecordTypeIds.get(dataSet.Origin__c);
Id DestinationId = acRecordTypes.get(dataSet.Destination__c);

System.debug('******** Data Set Name: ' + dataSetName );
System.debug('******** Origin RecordType Label: ' + dataSet.Origin__c + ', Origin RecordTypeId: ' +  OriginId );
System.debug('******** Destination RecordType Label: ' + dataSet.Destination__c + ', Destination RecordTypeId: ' + DestinationId );

You now have the origin and destination record type id's as determined by your custom settings!

You can add new mappings (data sets) as necessary without revisiting the code, but remember to spell the labels correctly, and keep the Origin labels unique.

 

Hope that helps!

All Answers

CaptainObviousCaptainObvious

After some playing around with Custom Settings, I think it may be possible to implement your idea...

 

I created a Custom Setting called "RecordTypeForwarding"
    Label RecordTypeForwarding
    Object Name RecordTypeForwarding
    Visibility Public
    Setting Type List

 

Next, I created 2 Custom Fields (these would be populated record type labels, so I set the data type to Text).

    Field Label Origin, Data Type Text(255)
    Field Label Destination, Data Type Text(255)

 

For each data set, I picked a name for the set and an existing record type label for the Origin and Destination.
(For my test I used a Contact record type label as the origin, and Account record type label as the destination)

 

    For the first data set:
         Name Set1
         Origin ContactRecordTypeLabel1
         Destination AccountRecordTypeLabel1
    For the second data set:
         Name Set2
         Origin ContactRecordTypeLabel2
         Destination AccountRecordTypeLabel2


Next, I created a global utility class which I could call from Apex:

 

global class util {    

    //Retrieve record type ids    
    public static Map<String,Id> getRecordTypeMap(String objType) {        
        Map<String,Id> recTypes = new Map<String,Id>();        
        for(RecordType recType:Database.query('SELECT id, name FROM RecordType WHERE sObjectType =\'' + objType + '\'')) {
            recTypes.put(recType.Name, recType.Id);
        }
        return recTypes;
    }

    //Retrieve record type labels    
    public static Map<Id,String> getRecordTypeLabelMap(String objType) {        
        Map<Id,String> rTypes = new Map<Id,String>();        
        for(RecordType recType:Database.query('SELECT id, name FROM RecordType WHERE sObjectType =\'' + objType + '\'')) {
            rTypes.put(recType.Id,recType.Name);
        }
        return rTypes;
    }

    //Retrieve all data sets from RecordTypeForwarding Custom Setting
    public static List<RecordTypeForwarding__c> getAllRecordTypeForwarding() {
    List<RecordTypeForwarding__c> allSets = RecordTypeForwarding__c.getall().values();
        return allSets;
    }

    //Retrieve a specific data set from RecordTypeForwarding Custom Setting
    public static RecordTypeForwarding__c getRecordTypeForwarding(String dataset) {
        RecordTypeForwarding__c dSet = RecordTypeForwarding__c.getValues(dataset);
        return dSet;
    }

}

How to use this:

 

//First determine the 'origin' RecordtypeId (you would set this in your controller)
Id rtype;

//Next, get the RecordType Label (we need this to search for the data set)
//Remember, in my example, all Origin Id's are form the Contact object
Map<Id,String> conRecordTypeLabels = util.getRecordTypeLabelMap('Contact');
String originRTypeLabel = conRecordTypeLabels.get(rtype);

//Using the RecordType Label we found, determine which Data Set to use
String dataSetName;
List<RecordTypeForwarding__c> dataSets = util.getAllRecordTypeForwarding();
for(integer i=0;i<dataSets.size();i++) { 
    if (dataSets[i].Origin__c == originRTypeLabel) {
        dataSetName = dataSets[i].Name;
        break;
    }
}

//Get the specific data set from the Custom Setting
RecordTypeForwarding__c dataSet = util.getRecordTypeForwarding(dataSetName);

//Create a map of record type ids for the Origin and Destination objects
Map<String,Id> conRecordTypeIds = util.getRecordTypeMap('Contact');
Map<String,Id> acRecordTypes = util.getRecordTypeMap('Account');

//Now assign the Origin and destination IDs:
Id OriginId = conRecordTypeIds.get(dataSet.Origin__c);
Id DestinationId = acRecordTypes.get(dataSet.Destination__c);

System.debug('******** Data Set Name: ' + dataSetName );
System.debug('******** Origin RecordType Label: ' + dataSet.Origin__c + ', Origin RecordTypeId: ' +  OriginId );
System.debug('******** Destination RecordType Label: ' + dataSet.Destination__c + ', Destination RecordTypeId: ' + DestinationId );

You now have the origin and destination record type id's as determined by your custom settings!

You can add new mappings (data sets) as necessary without revisiting the code, but remember to spell the labels correctly, and keep the Origin labels unique.

 

Hope that helps!

This was selected as the best answer
DCSDCS

Hi ,

 

Thanks for the details and the code. I implemented the same with a minor difference. When I added the data, I kept the name of the set same as origin. For ex:

 

    For the first data set:
         Name ContactRecordTypeLabel1 ( instead of Set1)
         Origin ContactRecordTypeLabel1
         Destination AccountRecordTypeLabel1
    For the second data set:
         Name ContactRecordTypeLabel2 (instead of Set2)
         Origin ContactRecordTypeLabel2
         Destination AccountRecordTypeLabel2

 

This avoided the extra logic to find the matching origin label.

This worked like a charm!!!

 

 

Thank you !