Cloning Records in Apex
When you clone an sObject in Apex, it copies all the fields populated in that Apex object, not necessarily all fields on the record. Let’s say you have a Lead with FirstName, LastName, Company, LeadSource and Status populated. If you do the following, the clone will not have LeadSource and Status cloned from the original record. It will use the default values for Leads. That is because those fields were not queried into the object.
/* query lead and then clone it */ lead l = [select id, firstname, lastname, company from lead where id = '00Q3000000aKwVN' limit 1][0]; lead l2 = l.clone(false, true); insert l2;
If you are cloning records, it can be frustrating to keep it updated as you add new fields to Salesforce. I generally want all new fields to be cloned too. I’ll code to any exceptions if needed. To help with this, I wrote myself a handy method to build me a SOQL statement and obtain all the writable fields.
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; } }
So if I want to clone the Lead I describe above, I’d do the following and this will ensure that I will clone all the fields on the Lead. Since the method only adds Creatable fields to the SOQL, I don’t have to worry about trying to set a formula field or system field and generating an error.
/* query lead and then clone it */ String soql = Utils.getCreatableFieldsSOQL('lead','id=\'00Q3000000aKwVN\''); lead l = (Lead)Database.query(soql); lead l2 = l.clone(false, true); insert l2;