1

I have a standard object (Lead) and a custom object (Country).

Lead - important fields

  • Address (where Country is stored)- I think this is Lead.Country
  • Country Lookup (a lookup field related to the custom object country) Lead.CountryLook__c (Lookup)
  • Lead Region (Where I would like to populate the Associated Region from country) Lead.Lead_Region__c (Text)

Country - important fields

  • Record ID (standard field) - Country.ID
  • Country Name (Record Name) Country.Name (text)
  • Associated Region - Country.Associated_Region__c (Picklist)

So I have an individual record for each country in the custom object (Say, Germany is the record/country name and the Associated Region is Europe. Mexico has an Associated Region of Latin America).

End goal - I want to write a trigger that looks at the Lead.Country and populates the Associated Region in the Lead Region field after leads are created. If the Lead.Country is blank... not sure what to return, what would best practice be? None?

I added the Lookup field to the Lead in an attempt to link the custom object with the standard object and use Process Builder, but was told by SF support I cannot do this, and need a trigger.

So how would I write an 'after update' trigger that looks at Lead.Country, compares it to Country.Name, and returns Country.AssociatedRegion in the Lead.LeadRegion field? Do I even need the Lookup field for this?

Any help would be greatly appreciated!

trigger UpdateLeadCountryLookup on Lead (after update, after insert) {
    for(Lead lead : Trigger.new) 
        {
        if (lead.country = country.name);
            {
                lead.countrylook__c = country.id;
            }
                {
                null;
                }
            
        }
}

5
  • Welcome to SFSE! Please take the tour and read How to Ask. Writing complete code based on requirements isn't what this site is really about (and such questions tend to be closed quickly). Providing details, and pointing to a very specific issue that you're having is the way to get the most out of this site/community. If you've started writing your trigger, please edit your question to include what you have so far.
    – Derek F
    Commented Dec 30, 2020 at 15:35
  • 1
    That said, once you have the lookup to your custom Country__c populated, you could use a simple formula field to pull the "region" value into your Lead record(s). It'd be simple enough to add to your trigger, but having less code means you have less that you need to test.
    – Derek F
    Commented Dec 30, 2020 at 15:38
  • Agree with @DerekF. No need for a trigger here based on your use case. Just use a formula field.
    – willard
    Commented Dec 30, 2020 at 16:19
  • 1
    @willard The trigger is needed to populate the lookup field though (or rather, Apex needs to be involved in some capacity. Field update actions for workflow/process builder can't set a lookup field value unless you hard-code an Id (just one Id) to be used)
    – Derek F
    Commented Dec 30, 2020 at 16:23
  • @Derek F, thank you for the info. Sorry, so new to this! I updated my question with the code I wrote, but I am not sure where to go from here.
    – Nicole
    Commented Dec 30, 2020 at 17:39

1 Answer 1

1

Since you're modifying the same object that your trigger is on, you'll actually want to use a before trigger context here (it means you don't need to perform explicit DML as long as you're modifying the instance of the record stored in trigger.new or trigger.newMap, and you don't need to worry about an infinite loop).

I think the piece that you're missing is how to get the Country__c records. The answer is by performing a query. You might instictively try to write something like

for(Lead l :trigger.new){
    List<Country__c> countries = [SELECT Id FROM Country WHERE Name = :l.Country];
    // ...
}

...but that's not the approach you should use. We're limited to 100 queries per transaction, so if you tried to insert or update more than 100 Leads, you'd run into trouble. Queries and DML are two things that should basically never appear inside of a loop.

The best practice here is to use the iterate-gather-query approach

// Iterate over the thing that contains the data you'll need for the query
List<String> countryNames = new List<String>();
for(Lead l :Trigger.new){
    // Gather the data in a collection
    countryNames.add(l.Country);
}

// Now, outside of any and all loops, perform the query
// We're making use of variable "binding" in the query
List<Country__c> countries = [SELECT Id, Name FROM Country__c WHERE Name IN :countryNames];

That's a big part of the battle, but now that we've got a list of Countries, how do we find the one we should use for a given lead?

The naive solution is to have a nested loop

for(Object 1){
    for(Object 2){
        if(object1.Field == object2.Field){
            // do work
        }
    }
}

That approach works, but is incredibly inefficient. If you have 100 leads, and 20 countries, you'll end up looping up to 20,000 times (with most iterations doing no work).

Whever you see something like that, you should be thinking "I should use a Map instead".

// The key of the map is the name of the country
// If you just need to match on a record Id, you can build a Map<Id, SObject> directly from a query
Map<String, Country__c> countryNameToCountry = new Map<String, Country__c>();
for(Country__c country :listFromCountryQuery){
    countryNameToCountry.put(country.Name, country);
}

// Doing that work allows you to easily find a match for your lead (if one exists)
for(Lead l :Trigger.new){
    if(countryNameToCountry.containsKey(l.Country)){
        // In here, there is a matching country
        // You can .get() from the map, and then set the country lookup on your lead
    }
}

The difference here is that you're looping a maximum of 100 + 20 = 120 times (2 orders of magnitude fewer times than the nested loop approach)

Once you have the appropriate country record, you could grab the region value from it (provided you included that field in your query for Country__c records) and set the appropriate field on your lead. That part could alternatively be handled by creating a formula field on Lead.

The benefits of the formula field approach are:

  • Slightly less code (which means less that you need to test)
  • If a country's region is updated, that change will automatically be reflected on the Leads (formula fields are recalculated every time the record is queried or viewed)
1
  • Derek, I wanted to thank you profusely for this detailed explanation. I took all your info and used it to put together this trigger with my team. Your best practices really helped us logic out what needed to be done on our side. Thank you again so much for taking the time to help me!
    – Nicole
    Commented Jan 20, 2021 at 18:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .