When a new Task is inserted(before insert) I want to get a lookup field from the object in it's 'whatId'(related to) and assign that to a lookup on the task. This is what I have, I'm pretty sure there is no danger of the 'whatId' being blank so don't worry about that:

    List<Id> pmgIds = new List<Id>();
    for(SObject temprecord : Trigger.New){
        pmgIds.add(temprecord.get('WhatId'));
    }

    for(Practice_Management_Guide__c pmg : [SELECT Id,Name,Client__c 
                                            FROM Practice_Management_Guide
                                            WHERE Id IN :pmgIds]){
        for(SObject temprecord:Trigger.New){
            if(temprecord.get('WhatId') == pmg.Id){
                temprecord.Client__c = pmg.Client__c;
            }
        }

    }

I'm curious is there a better way to do this ? Am I right in saying that you have to query to get other fields from an object related by 'WhatId' ?

  • 1
    WhatId can be null, but it would be ignored by the query anyways (it's only interested in values that are actually possible). You're right in presuming that you don't need to check for null in this case. – sfdcfox Nov 8 at 21:56
up vote 3 down vote accepted

Am I right in saying that you have to query to get other fields from an object related by 'WhatId' ?

Yes, you're entirely right. The only exceptions are a handful of core fields (Type and Name, off the top of my head) that you can access directly by querying through the What relationship.

As with any cross-relationship fields, you do have to query to obtain data from another object within your trigger. The trick with WhoId and WhatId (and OwnerId) is that the lookups are polymorphic, so you cannot query from the trigger through the relationship. Instead, you have to accumulate the Ids as you do here and write a separate query against a specific parent object.

I'm curious is there a better way to do this ?

There are some changes you need to make in your code. In particular, this double-loop structure is one of the least efficient ways to search.

Instead, do

Map<Id, Practice_Management_Guide__c> pmgMap = new Map<Id, Practice_Management_Guide__>(
    [SELECT Id,Name,Client__c FROM Practice_Management_Guide WHERE Id IN :pmgIds]
);

Then, when you loop back over Trigger.new, you can just do pmgMap.get(thisTask.WhatId).

You don't need to treat Trigger.new as untyped sObjects. You can assign it to a list of typed objects (List<Task>) and refer to fields directly on your Tasks rather than using get().

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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