Dynamic Record Cloning

Matt/ March 1, 2016/ Salesforce

I’m building a custom cloning functionality that needs to meet a few objectives, most important of which is being dynamic.  I don’t want to build these out for each object in our instance.

This is fine.  What I’ve done is build a class that reads the meta data of the sObject I want to clone.  The way to do this is to create a map of field names and field tokens and build up a SOQL query select statement with those fields.

Here’s a utility class with a method getCreatableFieldsSOQL() to accomplish just that:

public with sharing class Utils{ 
 
    // Returns a dynamic SOQL statement for the whole object, includes only creatable fields since we will be inserting a cloned result of this query
    public static string getCreatableFieldsSOQL(String objectName, String whereClause){
         
        String selects = '';
         
        if (whereClause == null || whereClause == ''){ return null; }
         
        // Get a map of field name and field token
        Map<String, Schema.SObjectField> fMap = Schema.getGlobalDescribe().get(objectName.toLowerCase()).getDescribe().Fields.getMap();
        list<string> selectFields = new list<string>();
         
        if (fMap != null){
            for (Schema.SObjectField ft : fMap.values()){ // loop through all field tokens (ft)
                Schema.DescribeFieldResult fd = ft.getDescribe(); // describe each field (fd)
                if (fd.isCreateable()){ // field is creatable
                    selectFields.add(fd.getName());
                }
            }
        }
         
        if (!selectFields.isEmpty()){
            for (string s:selectFields){
                selects += s + ',';
            }
            if (selects.endsWith(',')){selects = selects.substring(0,selects.lastIndexOf(','));}
        }
         
        return 'SELECT ' + selects + ' FROM ' + objectName + ' WHERE ' + whereClause;
    }
}

Great!  Now I’m ready to create a placeholder visual force page that I can call via url from a custom button.  The url is simple enough (note I’m using relative links here):

/apex/CloneSpecialWastePWS?sid={!Special_Waste_Profile__c.Id}

Creating that Visual Force page is easy enough – an otherwise blank canvass with a simple call to a doit() method:

<apex:page Controller="CloneSpecialWasteProfile" action="{!doit}"  showHeader="false" sidebar="false">

</apex:page>

And finally the controller for the Visual Force page.  Note the constructor that calls the above utility method, and the doit() method that returns a page reference.  Also, pay attention to how I grab the sid parameter from the URL:

public class CloneSpecialWasteProfile{

    private final Special_Waste_Profile__c p;

    public CloneSpecialWasteProfile() {
        String soql = Utils.getCreatableFieldsSOQL('Special_Waste_Profile__c','id=\'' + ApexPages.currentPage().getParameters().get('sid') + '\'');
        p = (Special_Waste_Profile__c)Database.query(soql);
   }
    
   public PageReference doit() {
        Special_Waste_Profile__c p2 = p.clone(false, true);
        insert p2;
        p2.Approval_Date__c = null;
        //Reset all of the fields I don't want to copy values for
        update p2;
        PageReference pageRef = new PageReference('/' + p2.Id);// + '/e?retURL=' + p2.Id);
        pageRef.setredirect(true);
        return pageRef;
    }
}

Then I add the button to the layout, and when it’s clicked I’m redirected to the view layout of a cloned record.  Implementing this for another object is as simple as creating a new Visual Force page and controller, and linking to that page from a new custom button on the layout for the sObject.

Share this Post

About Matt

Matt is a seasoned Salesforce Developer / Architect, with implementations of Sales Cloud, Service Cloud, CPQ, Experience Cloud, and numerous innovative applications built upon the Force.com platform. He started coding in grade 8 and has won awards ranging from international scholarships to internal corporate leadership awards. He is 37x Certified on the platform, including Platform Developer II, B2B Solution Architect and B2C Solution Architect.