function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Chris PulliamChris Pulliam 

Bulkify Apex Trigger on Task

I am very new to triggers. I made one that works in my sandbox, but from what I read I need to bulkify it so it doesn't fail when we mass update tasks. I know I'm supposed to pull SOQL out of the for loop. Beyond that I'm stuck.
 
trigger attachToAccount on Task (before update) {
for (Task myTask: Trigger.new)
  if (myTask.Subject != null){
   List<Lead> dupes = [SELECT Id, Lead_Accounts__c FROM Lead WHERE Id = :myTask.Whoid];
         if (dupes.size() > 0) {
                 myTask.WhatId = dupes[0].Lead_Accounts__c;
   } else {
           myTask.Subject = null;
}
}
}

 
Best Answer chosen by Chris Pulliam
JeffreyStevensJeffreyStevens
I think this will bulkify what you already have. 
 
trigger attachToAccount on Task (before update) {
  // Get Lead Ids from all of the triggered Tasks
  set<id> leadIds = new set<id>();
  for(Task myTask :trigger.new) {
    leadIds.add(myTask.whoId);
  }

  // Get Leads and build a map of <LeadId,Lead_Accounts__c>
  map<id,id> mLeadAccountIds = new map<id,id>();
  list<Lead> leads = [SELECT id, Lead_Accounts__c FROM Lead WHERE Id IN :leadIds];
  for(Lead l :leads) {
    mLeadAccountIds.put(l.id,l.Lead_Accounts__c);
  }

  // Update triggered tasks with Account Id
  for(Task t :trigger.new) {
    if(mLeadAccountIds.containsKey(t.whoId)) {
      t.whatId = mLeadAccountIds.get(t.whoId);
    }
  }

}

 

All Answers

James LoghryJames Loghry
Chris, 

What are you attempting to accomplish with your trigger here?  It appears you're looking for duplicates, but your trigger is currently only allowing 1 task per lead.  Is that what you really want, or do you want to filter on other dupe criteria as well?
Chris PulliamChris Pulliam
Hey James, no not looking for dupes (the 'dupes' references was from the trigger I copied and modified.

I am trying to populate the WhatId with the WhoId.Lead_Accounts__c field value on leads.
Lead_Accounts__c is a look-up field to the Account object on the Lead page.
The purpose is to get lead activity rolling up to the account to improve prospecting reporting.

 
William TranWilliam Tran
Well, if you want to pull it out, then it will take some work and you need to mimic what it looks like in the loop.

In the loop you are selecting for each myTask.Whoid.

So to take it out you can use Aggregate Functions like this:

ListofWhoids = loop through the triggers and get all the whoids.

AggregateResult[] groupedResults = SELECT count(*),  Lead_Accounts__c, Id  FROM Lead WHERE Id in: ListofWhoids

Loop through the triggers and assign myTask.WhatId = Lead_Accounts__c in the groupedResults. 

More about Aggregate Functions:
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_SOQL_agg_fns.htm

Bottomline: if you have problem refactoring, you might be okay as is, unless you have a batch process or a process that updates lots of tasks at once (at least hundreds).

As a common practice, if your question is answered, please choose 1 best answer.
But you can give every answer a thumb up if that answer is helpful to you.

Thanks
JeffreyStevensJeffreyStevens
I think this will bulkify what you already have. 
 
trigger attachToAccount on Task (before update) {
  // Get Lead Ids from all of the triggered Tasks
  set<id> leadIds = new set<id>();
  for(Task myTask :trigger.new) {
    leadIds.add(myTask.whoId);
  }

  // Get Leads and build a map of <LeadId,Lead_Accounts__c>
  map<id,id> mLeadAccountIds = new map<id,id>();
  list<Lead> leads = [SELECT id, Lead_Accounts__c FROM Lead WHERE Id IN :leadIds];
  for(Lead l :leads) {
    mLeadAccountIds.put(l.id,l.Lead_Accounts__c);
  }

  // Update triggered tasks with Account Id
  for(Task t :trigger.new) {
    if(mLeadAccountIds.containsKey(t.whoId)) {
      t.whatId = mLeadAccountIds.get(t.whoId);
    }
  }

}

 
This was selected as the best answer