1

I have Obj1 and Obj2 both having 20 fields of same API Names. For while creating Obj2 records I want to copy all those field values to Obj1. Is there any shortcut to do the coding instead of writing the whole thing.

Like below is the code.

    for (Integer i = 0; i < srList.size(); i++ ) {
         Database.SaveResult sr = srList[i];
            if (sr.isSuccess()) {

                 //Alstitem.External_ID_vod__c = actID+'-'+key;
                 for(Business_Plan_abv__c j: accMap.get(BpToInsert[i].Territory_Name__c))
                 { 
                 Business_Plan_Approval_Process_Data_abv__c bpdata = new Business_Plan_Approval_Process_Data_abv__c();
                 bpdata.Business_Plan_Approval_Process_abv__c= sr.getId();  
                 bpdata.Territory_abv__c= BpToInsert[i].Territory_Name__c;
                 bpdata.External_Id_abv__c = j.Account_abv__c+'_'+sr.getId();
                 bpdata.Account_abv__c = j.Account_abv__c;
                 bpdata.City_abv__c = j.City_abv__c;
                 bpdata.Comments_abv__c = j.Comments_abv__c;
                 bpdata.Call_Priority_Decile_abv__c = j.Call_Priority_Decile_abv__c;
                 bpdata.Call_Activity_Avg_of_last_3_quarters_abv__c = j.Call_Activity_Avg_of_last_3_quarters_abv__c;
                 bpdata.Business_Planner_Flag_abv__c = j.Business_Planner_Flag_abv__c;
                 bpdata.Biologic_Index_last_6_months_abv__c = j.Biologic_Index_last_6_months_abv__c;
                 ......................?? Instead of writing like this, is there any shortcut way to copy field values.
}
                 insbpdata.add(bpdata);
            }
        }
0

3 Answers 3

2

This is a good use case for Field Sets or, if you've concerned that some values or field names may change a bit in either side, Custom Metadata.

I will walk you through Field Sets.

Field Sets

First, create a field set in Business_Plan_abv__c and call it something like Approval_Process_Data_Fields. Put all of the fields in it that you want to copy over.

Then, in your code you can do something like this:

Schema.FieldSet fieldSetToCopy = Schema.SObjectType.Business_Plan_abv__c.FieldSets.Approval_Process_Data_Fields;
for (Schema.FieldSetMember dataField : fieldSetToCopy.getFields()) {
  bpdata.put(dataField.getFieldPath(), j.get(dataField.getFieldPath()));
}

This assumes that the fields will always share a name. Once that is no longer the case, this solution is unusable without some hacking. Also, note that there is no compile-time documentation about that requirement anywhere in the code - you'd need to write a test for all the fields in that FieldSet.

Custom Metadata

A more robust way to deal with this is Custom Metadata.

Declare a custom metadata type with two Entity-Field pairs. One pair is the "From" and one pair is the "To".

You can then map each field in the Custom Metadata records (and possibly some transformation information). In your code, you'd loop through the Custom Metadata records, doing something like:

for (Mapping__mdt mapping : [SELECT From_Field__c, To_Field__c
                             FROM Mapping__mdt
                             WHERE From_Entity__c = :Schema.SObjectType.Business_Plan_abv__c 
                             AND To_Entity__c = :Schema.SObjectType.Business_Plan_Approval_Process_Data_abv__c
                             AND Use_Case__c = 'something']) {
  Object oldData = j.get(mapping.To_Field__c);
  bpdata.put(mapping.From_Field__c, oldData);
}

You'll still need tests, of course - and probably validation rules to ensure that the mapped fields are the same type, but you can here expand the mapping to include a transformation if needed (I suppose you can do that with FieldSets, too).

2

unfortunately without such big construction you can't do it. As a way to achieve it more elegant, you can use mapping. In your case, as I see, that names of fields are exactly the same, you can use Set. For example :

Set<String> sameFields = new Set<String>{
        'Account_abv__c',
        'City_abv__c',
        'Comments_abv__c',
        'Call_Priority_Decile_abv__c',
        'Call_Activity_Avg_of_last_3_quarters_abv__c',
        'Business_Planner_Flag_abv__c',
        'Biologic_Index_last_6_months_abv__c'
    };

    if (sr.isSuccess()) {
        for(Business_Plan_abv__c j: accMap.get(BpToInsert[i].Territory_Name__c)){
            Business_Plan_Approval_Process_Data_abv__c bpdata = new Business_Plan_Approval_Process_Data_abv__c();
            bpdata.Business_Plan_Approval_Process_abv__c= sr.getId();
            bpdata.Territory_abv__c= BpToInsert[i].Territory_Name__c;
            bpdata.External_Id_abv__c = j.Account_abv__c+'_'+sr.getId();
            for(String samefield :sameFields){
                bpdata.put(samefield, j.get(samefield));
            }
        ...
    }
6
  • But how come bpdata.put(samefield, j.get(samefield)); and bpdata.Account_abv__c = j.Account_abv__c; bpdata.City_abv__c = j.City_abv__c; bpdata.Comments_abv__c = j.Comments_abv__c; bpdata.Call_Priority_Decile_abv__c = j.Call_Priority_Decile_abv__c; bpdata.Call_Activity_Avg_of_last_3_quarters_abv__c = j.Call_Activity_Avg_of_last_3_quarters_abv__c; bpdata.Business_Planner_Flag_abv__c = j.Business_Planner_Flag_abv__c; be the same? Jul 19, 2017 at 17:31
  • API names of fields are the same, and they are stored as String Jul 19, 2017 at 17:38
  • Does not look to me like all the field API names are the same
    – Eric
    Jul 20, 2017 at 5:44
  • @Eric for example? Jul 20, 2017 at 6:00
  • @AlexanderBerehovskiy Business_Plan_Approval_Process_abv__c is set to the Id field. Just look through, there are s few that are not matched to same exact API name
    – Eric
    Jul 20, 2017 at 6:03
2

The most efficient way is to use the SObject Constructor design:

 insbpdata.add(new Business_Plan_Approval_Process_Data_abv__c(
     Business_Plan_Approval_Process_abv__c= sr.getId(),  
     Territory_abv__c= BpToInsert[i].Territory_Name__c,
     External_Id_abv__c = j.Account_abv__c+'_'+sr.getId(),
     Account_abv__c = j.Account_abv__c,
     City_abv__c = j.City_abv__c,
     Comments_abv__c = j.Comments_abv__c,
     Call_Priority_Decile_abv__c = j.Call_Priority_Decile_abv__c,
     Call_Activity_Avg_of_last_3_quarters_abv__c = j.Call_Activity_Avg_of_last_3_quarters_abv__c,
     Business_Planner_Flag_abv__c = j.Business_Planner_Flag_abv__c
 ));

There are shorter ways of doing this (e.g. via a field set), but this is the most efficient design (at minimum 2x more efficient than shorter code would be). You should use this design whenever possible so your code will run as quick as possible.

4
  • Speed is not the only limiting factor in code. Often, maintainability is more important. The FieldSet route (or using Custom Metadata) is much more maintainable. Jul 19, 2017 at 21:01
  • @CharlesKoppelman I like maintainability, but the performance penalty for 20+ fields is statistically significant. It can be the difference between a CPU governor limit or not. This technique was important when we had a 200,000 script line limit, and it's still important now. Until/unless the inter-statement delay is significantly improved, this is still an important optimization.
    – sfdcfox
    Jul 19, 2017 at 21:14
  • @CharlesKoppelman can you please also let me know about the fieldset way for this? I am unable to use this method though it is an answer for some unavoidable case in my design. Jul 20, 2017 at 10:15
  • @SFDC_Learner ok, done Jul 20, 2017 at 14:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.