I have a requirement to deep clone (Parent -> Child -> Grand Child) records by clicking a button at the Parent Level. I believe Salesforce supports only Clone at the Parent Level, it does not have Deep Clone Out Of the Box. Has anyone ever built it ?

6 Answers 6


You could leverage the power of External Ids to join up the objects and use the sObject Clone Method. External Ids let you dynamically match the records, without having to explicitly set the ids of the parent records being created in the clone.

Let's take the example of Account -> Opportunity -> Opportunity Product

List<Account> accts = new List<Account>{};
List<Opportunity> opptys = new List<Opportunity>{};
List<OpportunityLineItem> olis = new List<OpportunityLineItem>{};

Account acc = [Select Id, Name .... from Account];

Account accNew = acc.clone(false, true); //See sObject Clone Method
accNew.ExternalId__c = acc.Name + Datetime.now(); // set unique external Id

for(Opportunity opp : [Select Id, Name, ... (Select Id, ... from OpportunityLineItems) from Opportunity where AccountId = :acc.Id]){
Opportunity newOpp = opp.clone(false, true);
newOpp.ExternalId__c = opp.Name + Datetime.now(); //set unique external id

newOpp.Account = new Account(ExternalId__c = accNew.ExternalId__c); //set parent ref


for(OpportunityLineItem oli : opp.OpportunityLineItems){

OpportunityLineItem oliNew = oli.clone(false, true);
oliNew.Opportunity = new Opportunity(ExternalId__c = newOpp.ExternalId__c); //set parent


insert accts;
upsert opptys; //upsert matches to accounts using external id
upsert olis; //upsert matches to opportunities using external id
  • Very useful (having recently discovered the power of Externa IDs I was not aware of, such as being able to insert a parent and child(ren) all at the same time. W00t!
    – AMM
    Nov 23, 2016 at 21:29

Apex: In terms of building a solution in Apex code, there is some partial support for this you can leverage. The SObject.clone method and also JSON support can help build solutions to achieve this in code, but there is no platform deep clone.

SObjectDataLoader.cls: I've recently leveraged the JSON Apex support to implement a native SObject import/export that has the same requirement. Take a look at SObjectDataLoader. Which will perform a deep serialize (and thus deserialize) of child records and related records. By combing the two operations like so you can implement a generic Apex deep clone by passing only Id's of the master records.

Set<ID> clonedMasterIds =
     SObjectDataLoader.deserialize( SObjectDataLoader.serialize(masterIdsToDeepClone) );

You can read more about this here, cloning is one of many use cases that could be applied. The serialize and deserialize methods are configurable to control what gets cloned and/or resolved during deserialization.

enter image description here

AppExchange: There is also a number of AppExchange solutions if you wanted something already pre-built.

  • Andrew - That's indeed great work. From your blog, I came to understand that we need to pass set of Ids to serialize method. Something like this: Set<ID> clonedMasterIds = SObjectDataLoader.deserialize( SObjectDataLoader.serialize(masterIdsToDeepClone) ); However, when I do that, I get some "implementation error". Can you tell me how to fix this? Also, will it clone the master object, child and grandchild object? Any chances of hitting the governor limit???? May 26, 2015 at 7:14
  • Thanks! It might be best to post a GitHub issue on the repo for the library, with more details on the implementation issue. But yes, it will try to reach out to child and grandhild, there are lots of chances of hitting governors with large datasets! ;-) May 26, 2015 at 10:29

Well I guess to accomplish the same just have to maintain the order in which DML is issued. Since with every DML calls the Id field of sobject is automatically populated. You can then leverage the power of collection(which stores the reference of object rather than value) to map the child and grand child records.

Extending the *Account -> Opportunity -> Opportunity Product further.

The Util Class

class AccountDeepCloneUtil 
    public static void cloneAccount(Account acc) 
        Map<Opportunity,List<OpportunityLineItems>> OpportunityLineItemsMapping = new Map<Opportunity,List<OpportunityLineItems>>();
        List<Opportunity> newOpportunityList = new List<Opportunity>();
        List<Opportunity> oppList = [Select Id, Name, ... (Select Id, ... from OpportunityLineItems) from Opportunity where AccountId = :acc.Id];
        Account newAcc = acc.clone(false, true); //do a deep clone
        //insert the account record
        insert newAcc;
        for(Opportunity opp : oppList){
            Opportunity newOpp = opp.clone(false, true); //do a deep clone
            newOpp.Account = newAcc.Id;
        //insert opportunity
        insert newOpportunityList;

        for(Opportunity opp :OpportunityLineItemsMapping.keySet()){
            for(OpportunityLineItemoppLineItem : OpportunityLineItemsMapping.get(opp)){
                OpportunityLineItem.OpportunityId = opp.Id;

        insert OpportunityLineItemsMapping.values();

How to use the class?

AccountDeepCloneUtil.cloneAccount([Select Id, Name .... from Account WHERE Id=<your record Id>]);

PS: The code written just using a notepad. Hence may not actually compile.Please feel free to make any changes.

  • clean code, only problem with the last insert I had to flatten the values list : List<OpportunityLineItems> OppLineItemsList = new List<OpportunityLineItems>(); for (List<OpportunityLineItems> collection : OpportunityLineItemsMapping.values()) OppLineItemsList.addAll(collection);
    – nassim
    Apr 12, 2022 at 23:54

Parent>Child>Grand child>Great grand child can be achieved through couple of inner classes which will be served as a storage while we iterate through and identify all levels of parent and child we wish to clone. Need to make use of Custom Settings.

  • 1
    What needs to change in Custom Settings? Also, got any examples of this code pattern to share?
    – Jagular
    Dec 2, 2014 at 14:37

I had a similar requirement and happened to see this post. I think the solutions given by @techtrekker and @Avidev9 should work but I have gone with the solution of @Avidev9 which worked fine for me. I had to clone three levels deep and was able to implement. This is entirely based on the concept of "Object Pass by Reference".

The only reason I did not go with the solution of @techtrekker is, I don't want to introduce additional external id fields.

Just thought of sharing my idea..


Here is an app that does that. For now it clones Parent and Child, which is what most of the orgs need.

Clone any object with any related list in just 2 clicks! See this app for more info: https://appexchange.salesforce.com/listingDetail?listingId=a0N3000000B39tWEAR

  • 1
    Looks interesting but you should provide some kind of disclaimer (whether you're related to the company behind this paid app or not, looks quite expensive). Also this doesn't answer the question 100% as the OP needs to clone grandchildren records too...
    – eyescream
    Jun 1, 2013 at 23:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .