1

I have to iterate over 2500+ tasks and depending if it's an email (Type='Email') then I need to grab the owner's email from the related Lead/Contact associated with that task.

Right now this is my code:

Map < Id, Task > TaskMap = new Map < Id, Task > ([SELECT Id, Whoid, Type, Subject, Description from Task WHERE Id In: TaskId]);

For (Task t: TaskMap.values()) {
    if (t.whoId != Null) {
        string whoid = t.whoId;
        boolean IsLead = whoid.startsWith('00Q');
        boolean IsContact = whoid.startsWith('003');
        // Is my task an Email ?
        if (t.Type != Null) {
            if (t.Type == 'Email' && t.Subject != Null) {
                string subject = t.Subject;
                if (subject.startsWith('Email:'))
                   if (IsLead) {
             // Give me the owner's email of the lead associated with that task
             // Check if that email address is contained in the task's description.
            // Do something else
           }

What is the best way to write these 3 lines without having a query inside a for loop and without hitting a governor limit when there are imports of 3k tasks?

  • You should add as much as filters in WHERE clause of SOQL – Raul Mar 15 '17 at 18:54
  • And which 3 lines are you referring to? – Raul Mar 15 '17 at 19:00
  • These 3 lines: // Give me the owner's email of the lead associated with that task // Check if that email address is contained in the task's description. // Do something else – The Ghost Mar 15 '17 at 19:12
  • What is do something else? – Raul Mar 15 '17 at 19:19
  • Do something else is updating the lead Email_Opt_out field to False. (I'm adding that lead to a list and doing an update outside of the for loop.) – The Ghost Mar 15 '17 at 19:32
3

I would filters in WHERE clause of SOQL to narrow down the query rows as per best practice.

If you are aware of and use polymorphic query, life would be much easier.

Here is an example for your reference:

// This SOQL takes care filters on Who, Type and Subject
/* 
  Who.Type IN ('Lead', 'Contact')-
      this filter is unnecessary 
      but have just added to demonstrate its capabilities.
*/
for(Task objTask: [SELECT Id, WhoId, Subject, Description, 
     TYPEOF Who
        WHEN Lead THEN Email
        WHEN Contact THEN Email
      END
    from Task 
    WHERE WhoId != null AND
    Who.Type IN ('Lead', 'Contact') AND 
    Type = 'Email' AND 
    Subject LIKE 'Email:%']) {

    String strTasksWhoOwner = '';
    // avoid using key prefix, instead use instanceof
    if(objTask.Who instanceof Contact) {
        System.debug('In Contact');
        Contact objContact = objTask.Who;
        // here access Email field for comparison
        System.debug('objContact.Email: ' + objContact.Email);
        strTasksWhoOwner = objContact.Email;
    } else if(objTask.Who instanceof Lead) {
        Lead objLead = objTask.Who;
        // here access Email field for comparison
        System.debug('objLead.Email: ' + objLead.Email);
        strTasksWhoOwner = objLead.Email;
    }

    // your filter for Owner field
    if(String.isNotEmpty(strTasksWhoOwner)) {

    }
}

Avoid use of key prefix to match an object, instead use instanceof wherever applicable.

Links for reference:

  1. Working with Polymorphic Relationships in SOQL Queries
  2. SOQL Polymorphism, or How I Learned to Love the Polymorphic Relationship

Added based on your comments:

Quoting from documentation:

Currently, this feature is only available in sandbox environment, This feature is not available in production organization. Please contact Support to get this feature enabled in your sandbox organization if you would like to test it. Once this feature is generally available (GA), support will be able to enable this in production (paid) organizations too.

Alternate solution would be:

  1. Iterate over task list and collect WhoId's
  2. Form a Map of querying by Lead and Contact based on collected WhoId.
  3. Iterate over same task list queried in #1, and fetch appropriate Lead and Contact fields from map.
  • On this line: for(Task objTask: [SELECT Id, WhoId, Subject, Description, TYPEOF Who WHEN Lead THEN Email WHEN Contact THEN Email END from Task WHERE WhoId != null AND Who.Type IN ('Lead', 'Contact') AND Type = 'Email' AND Subject LIKE 'Email:%']) I get an error that says: SOQL TYPEOF expressions are not supported in this organization. (When I try to save the class) Do I need to enable this somewhere in my Org? Does TYPEOF support "Who" instead of "What"? Thanks. – The Ghost Mar 16 '17 at 20:25
  • Try upgrading API version of your class to the latest if not already? – Raul Mar 16 '17 at 20:50
  • I'm using the latest version already, support also told me this is not going to work in Production because Polymorphic queries are not supported. I will have to check if it is a Lead or a Contact and then work from there. I will work on it tomorrow and hopefully I can mark your question as the best answer. Thanks man! – The Ghost Mar 16 '17 at 21:57
  • Crap, never knew that this is still GA and requires a request to be enabled in sandbox. Hope you get better answer to your problem if you didn't get already. Let us know. – Raul Mar 17 '17 at 14:00
  • On this line: Lead objLead = objTask.Who; I get an error message. Invalid conversion from runtime type Name to Lead. How would you solve that one? The rest works really well – The Ghost Mar 17 '17 at 17:16

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.