4

I have objA and objB . objA has around 350 fields and some fields in objA starts as SVCM__xyz__c but those fields in objB starts as xyz__c . Now i want objB to be mirrior of objA. I need to write a trigger to objA to perform this task. Need to create mapping between them. fields in objB are subset of objA.

I am trying to avoid hardcoding field names into the trigger. I did fetch all the fields and removed SCVM__ from the each field in ObjA. Now how to create mapping between fields. Code I have so far is below.

public with sharing class CloneRecordToWorkOrderHandler { 

Map<String,Schema.SObjectField> mapFieldMapManaged; 
static Map<String,String> mapLabelToFieldSV; 
Map<String,Schema.SObjectField> mapFieldMapNew; 
static Map<String,String> mapLabelToFieldWO; 

public CloneRecordToWorkOrderHandler() { 
   mapFieldMapManaged = Schema.getGlobalDescribe().get('SVMXC__Service_Order__c').getDescribe().Fields.get‌​Map();
   mapFieldMapNew = Schema.getGlobalDescribe().get('Work_Order__c').getDescribe().Fields.getMap();
   String key = ' '; 
   String value = ' '; 
   mapLabelToFieldSV = new Map<String,String>(); 
   mapLabelToFieldWO = new Map<String,String>();

   for(String s:mapFieldMapManaged.keySet()) { 
      key = mapFieldMapManaged.get(s).getDescribe().getLabel(); 
      value = mapFieldMapManaged.get(s).getDescribe().getName();
      if(mapFieldMapManaged.get(s).getDescribe().isUpdateable()) mapLabelToFieldSV.put(key, value); 
   }

   for(SVMXC__Service_Order__c so : lstWOManage.values()) { 
      newWO = new Work_Order__c(); 
      newWO.put('SVXMX_Record_Id__c',so.get('Id')); 
      for(String lbl: mapLabelToFieldSV.keySet() ) { 
         fieldSV = mapLabelToFieldSV.get(lbl); 
         if(mapLabelToFieldWO.containsKey(lbl)){ 
            fieldWO = mapLabelToFieldWO.get(lbl); 
            newWO.put(fieldWO ,so.get(fieldSV)); 
         } 
         else continue; 
      }

      RecordType rtSV = [Select Name From RecordType where Id = :so.RecordTypeId limit 1];
      RecordType rtWO = [Select Id From RecordType where Name = :rtSV.Name and sObjectType = 'Work_Order__c' limit 1]; 
      newWO.put('RecordTypeId',rtWO.Id); lstToInsert.add(newWO); 

   }

   insert lstToInsert; 

} 
}
6
  • 1
    Are the fields in ObjB of the same type (text, dec, integer, etc,) as their equivalents in ObjA and do they hold the same values (in essence is ObjB a mirror of ObjA)? Do you actually need to create a map or do you simply need to update the fields on both objects with the desire to use a single trigger? I ask some of these questions because if the values are the same, you don't necessarily need a map since the updates to both may already be in trigger.new and could be done in for loops for each one. That said, traditional architecture would recommend two triggers; one for each object.
    – crmprogdev
    Oct 3, 2014 at 6:45
  • 1
    For the benefit of all, please edit your question with answers to the above questions as best you can. If you have any code you've already written that would be helpful too in order to get more specific feedback. Thank you.
    – crmprogdev
    Oct 3, 2014 at 6:47
  • No they don't have same number of fields(objB is subset of ObjA). Now what exactly i need to do is .. write a trigger on objA that will do all the task(inser/delete/update/undelete records) on objB that are performed on objA . Thanks a lot for replying to this... Oct 3, 2014 at 13:49
  • fields in objB have same name as that of objA. Oct 3, 2014 at 14:05
  • I have objA and objB . objA has around 350 fields and some fields in objA starts as SVCM__xyz__c but those fields in objB starts as xyz__c . Now i want objB to be mirrior of objA. I need to write a trigger to objA to perform this task. Need to create mapping between them. fields in objB are subset of objA. Oct 3, 2014 at 20:53

2 Answers 2

0

From looking at your code, here's what I see that you still need to do along with some questions that you'll need to answer:

1) If you're not calling this class from a separate trigger, you'll want to set it up using something like the Tidy Trigger Pattern or something similar where you'd basically have 6 methods and you'd be passing trigger.net, trigger.old, trigger.newmap and trigger.oldmap along with the Booleans for the type of trigger operation (AfterInsert, AfterUpdate, AfterDelete, etc):

public void bulkBefore()
{

}

public void bulkAfter()
{

}

public void afterInsert(SObject so)
{

}

public void afterUpdate(SObject oldSo, SObject so)
{

}


public void afterDelete(SObject so)
{

}   

public void afterUnDelete(SObject so)
{

}   

2) Right now, you're really only addressing the code for creating a new objB record for after insert of a new objA record.

What you've done is mapped the fields that have the isUpdateable attribute set to true on them for objA in this line:

if(mapFieldMapManaged.get(s).getDescribe().isUpdateable()) mapLabelToFieldSV.put(key, value);

That's great, but you may also need to know things from fields in objA that aren't updatable when creating new records for objB.

3) You've done the describe call for objB. It appears to me that you're going need a map of the fields from objB that are creatable to use for inserting the new record. You may also need to know which ones are required. Those same fields will likely have the same attribute applied to them on objA; something for you to think about.

In thinking about what you'll need for the afterUpdate, you're also going to need a different map for the fields in objB of what's updatable. You may as well create the code for collecting all of these these maps at the same time since you'll have done the describe call.

4) What I also don't see is how you're going to determine the relationship between objA and objB. If these aren't parent child records of some kind through a M-D relationship, which I doubt is the case as I wouldn't expect a 1 to many relationship, I'd expect there to be a URL link field or some other key that creates a link between the two.

You're going to need to know what that field is and how to find it in order to match records. In my experience with mirrored objects, after you insert a new record for the 2nd object, you then often obtain the insert results and then update a field on the records in the first object (objA) with those Ids. You'll need to figure out if you need to do that. Unless you set a boolean flag on a Public Boolean of some kind, your trigger will fire twice when you do.

5) Once you have maps for both of the objects and know how to link the records correctly, you can then do matching using nested for loops to iterate through the field sets along with trigger.newmap to create the new records.

You'll want to do the same on AfterUpdate using only the fieldset maps you know are needed from both objects. I hope its apparent that fieldset maps collected with filters on update only attributes will be needed to perform the update matching which is different than what's needed to create the after insert records. For this part, I'd also expect you'd want to do some kind of filtering to test to discover which fields have values that have been updated doing something like

trigger.newmap.field(n) != trigger.oldmap.field(n)

before adding that field name to a list of fields for an objA record Id on which to update the value in the associated fields of an objB record.

I hope you'll post your final code for everyone to see when you're finished.

8

SObjects have get and set methods which you can use to set/get the values of fields.

If the fields are of the same type and the only difference is that objA has a prefix in the field API names, i.e. SVCM__ then you can just loop over the field names in the objB list (which you say you have) and then add the prefix when getting fields from objA:

for(String field : objBFields)
{
  objBRecord.set(field, objARecord.get('SVCM__' + field));
}

If the field names have other variances and you need a full map then you could implement this you could use a string map to work out what goes where:

Map<String, String> AFieldToBField = new Map<String, String>
{
  'SVCMP__xyz__c' => 'xyz__ c',
  'SVCMP__abc__c' => 'abc__ c'
};

for(String key : AFieldToBField.KeySet())
{
    objA.put(key, objB.get(key));
}

Obviously this is only going to work if the fields are of the same types on each object, otherwise you're going to need to deal with conversion as well.

4
  • We have around 350 fields.. So it won't be possible to create map for this. Thanks Oct 3, 2014 at 15:11
  • As an alternative to a hard coding the map, you could use a custom setting to store the mappings. Oct 3, 2014 at 15:18
  • Hi Daneil , What i have is fields of objA and fields of objB in list , is there any which through which i can map them . Remember fields in objB is subset of fields in objA. Oct 3, 2014 at 16:21
  • 1
    If they are an exact subset, you could use a fieldset on Obj B - then use @LaceySnr's solution - do a get for each field in the field set from objA and perform the action you need to take Oct 3, 2014 at 16:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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