0

I'm working on a requirement as follows: Whenever an Opportunity is created or edited, its custom region picklists (Region__c) should be overwritten with the Account region picklists (Region__c).

Trying to develop a trigger that would satisfy this requirement.

Whenever an Opportunity is created or edited, check to see if any of the custom Region__c picklists are NULL. If any are NULL, overwrite all picklist fields with corresponding data from the Account object.here's what I have so far:

trigger UpdateOpptyPicklists on Opportunity(Before Insert, Before Update) {
  for(Opportunity o: Trigger.new){
     Account a = [select id,Region__c,Area__c, Division__c from Account where Id=:o.AccountId];

    if(o.Region__c == NULL || o.Area__c == NULL || o.Division__c == NULL){

      o.Region__c=a.Region__c;
      o.Area__c = a.Area__c;
      o.Division__c=a.Division__c;
    }
  }
}

How can I bulkify this trigger

2

This would bulkify the trigger. The key is to leverage Salesfroce collections (Lists, Sets, Maps) to hold your accounts, so you only have to use a single SOQL query, as opposed to a new SOQL query each iteration in your original trigger. I am using a map to collect all the accounts and needed fields from the accounts, and then looping through the opps to reset there values if necessary.

trigger UpdateOpptyPicklists on Opportunity(Before Insert, Before Update) {

    map<Id,Account> accountMap = new map<Id,Account>();

    for(Opportunity o : Trigger.New) {
        accountMap.put(o.AccountId, null);
    }
    accountMap.remove(null);
    accountMap.putAll([Select Id, Region__c, Area__c, Division__c from Account where Id In : accountMap.keyset()]);

    for(Opportunity o: Trigger.new){
        if(o.AccountId == null){
             continue;
        }
        if(o.Region__c == NULL || o.Area__c == NULL || o.Division__c == NULL){
            o.Region__c = accountMap.get(o.AccountId).Region__c;
            o.Area__c = accountMap.get(o.AccountId).Area__c;
            o.Division__ c = accountMap.get(o.AccountId).Division__c;
        }
    }
}
  • This works when I create a new Opportunity. But it spits out an error when I try to save the Opportunity without selecting an Account. I still want to be able to create an Opportunity without selecting an Account. Also, it doesn't trigger when updating the Opportunity. How would I accomplish this. Thanks! – user8556 May 27 '14 at 16:31
  • Edited the code to not throw an error on an opportunity with no Account. The code should work for an update. – Chris Duncombe May 27 '14 at 16:57
  • No prb. Glad to help. – Chris Duncombe May 27 '14 at 17:09
2

The key to making bulkified triggers is to make good use of key-value Maps.

So what I'd do is iterate through the (list of new) Opportunities and get a list of all the related Accounts:

List< ID > AccIDs = new List< Id >(); For (Opportunity o: Trigger.new){ AccIDs.add(o.AccountID); }

Then do a single query to grab all the Accounts, and save them into a Map

Map< Id, Account > AccMap = new Map< Id, Account >([Select Id, Region__c, Area__c, Division__c from Account where ID in :AccIDs]);

Now you can reference any account with the syntax AccMap.get(o.AccountID)

So what you want to do now is iterate through the opportunities again, and pull in the Account fields where needed:

List< Opportunity > updateList = new List< Opportunity >(); For (Opportunity o: Trigger.new){ if(o.Region__c == NULL || o.Area__c == NULL || o.Division__c == NULL){ o.Region__c = AccMap.get(o.AccountID).Region__c; o.Area__c = AccMap.get(o.AccountID).Area__c; o.Division__c = AccMap.get(o.AccountID).Division__c; updateList.add(o); } } update(updateList);

Hopefully that's enough to set you on the right track. It takes a little practice to wrap your head around bulkification :)

  • Can you update this to use this pattern Initialising Maps from Queries rather than a loop? – Keith C May 27 '14 at 16:05
  • Oh yeah, that's a nice little trick. Never knew about that! I updated the above code with that change. – DownstairsB May 27 '14 at 18:05
1

Do this loop twice:

for(Opportunity o: Trigger.new){

The first time, get a Set of all of the different AccountIds. After that, query for all of the associated accounts and place them in a Map with the Id as a key. Loop through it a second time, use the map to grab the associated Account by it's Id.

Part 9: https://developer.salesforce.com/page/Apex_Code_Best_Practices

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.