2

I'm am having a ridiculous time finding basic Trigger examples (background: no official training, have books, have experience elsewhere, figuring this out on my own).

I am trying to write an insanely simple trigger that does a Lookup. CountryList is on Lead, I have made a custom object CountryLists. I want to verify if CountryList from Lead exists in the field "Country" in object CountryLists.

I have tried several iterations of code and keep getting mixed up on my initial Trigger.new call versus looping through either the Custom Object or the Leads to find if it yields a null or not. Literally, IF NOT NULL, then (do things to the Lead). That's it.

Does someone have an example or source of examples? Googling such things is a crap-shoot anymore.

Thanks so much.

ADDED: EXPANDED REASONING

One of the things I will do if NULL is found is put a value "(Undefined)" into field REGION__C on the Lead.

As well, if it is NOT NULL, I will be populating REGION__C on the Lead with an equivelent Region variable from the matching CountryLists entry.

Effectively.... United States of America will get a Region__c _ of "North America", as an example. Currently this is done via (many) workflows (for over 200 countries, INCLUDING all their misspelled/alternate texts). Our many lead sources are NOT consistent of course. Having this in a custom object makes sense. I'm just missing the actually "does Lead.Countrylist_c exist inside CountryLists.Country_c? IF SO, do this, IF NOT, do that." :-/

SOLUTION CREATED FROM HELP GIVEN BELOW:

trigger Country_List_Lookup_LEADS on Lead (before insert,before update) {

    Set<String> countryNames = new Set<String>();

    for( Lead l : trigger.new ) {
        if( l.CountryList__c != null) {
            countryNames.add( l.CountryList__c );
        }
    }

    // Now we have a set of unique country names we want to verify, time to look them up.
    // I plan to build a map of the "match field" -> "full reference object"

    Map<String, Country_List_Reference__c> validCountries = new Map<String, Country_List_Reference__c>();

    for( Country_List_Reference__c obj : [SELECT  Id, 
                                        MTI_Region__c,
                                        Country__c 
                                            FROM    Country_List_Reference__c 
                                            WHERE     Country__c IN :countryNames] ) {
        validCountries.put( obj.Country__c, obj );
    }

    // We have all the reference data we need, last loop on the each lead

    for( Lead l : trigger.new ) {

        if( l.CountryList__c != null ) { // there IS a countrylist entry to deal with... so...

            if( validCountries.containsKey(l.CountryList__c) ) { // found it, do your stuff
                l.Region__c = validCountries.get(l.CountryList__c).MTI_Region__c;

            } else { // do stuff when NOT found
                l.Region__c = '{UNKNOWN COUNTRY LIST ENTRY)';

            }
        } else { // there IS NOT a countrylist entry to deal with...
            l.Region__c = '(COUNTRY LIST IS EMPTY)';
        }

    }


}

I will be expanding the IF...ELSE section at the bottom, but this got the job done. Special thanks to @EyeScream and those who offered their input as well. ;-)

5
  • 2
    You may not need a trigger for this. Are you trying to validate that the country is in the list or do you want to do more if it is in the list? I think you can do it with a validation rule and the VLOOKUP function. Oct 30, 2012 at 19:56
  • Expanding my reason for this trigger... standby.
    – AMM
    Oct 30, 2012 at 19:58
  • A custom setting would make it a lot easier, soql inexpensive and is great for lookingup reference data. Oct 30, 2012 at 20:08
  • @techtrekker - true, so true. But in my experience such reference objects always grew eventually ("can we have an 'active' flag and country ISO code?", "can we have 'proper name' field for each misspelled one?", "can we manage it ourselves instead of asking admins to modify settings?"... Eh.
    – eyescream
    Oct 30, 2012 at 20:12
  • @eyescream that's a totally different topic. And an object is as vulnerable to scope creep as a custom setting. ;) Oct 30, 2012 at 20:18

2 Answers 2

3

Assuming the Country_List_field__c field on the lead is a freetext, something like this should do.

Note: I've picked stupid names to distinguish between the field on the Lead (Country_List_field__c) and the reference object you want to check it against (Country_List_object__c). Not verified for syntax errors too, just a rough nudge in hopefully right direction.

Set<String> countryNames = new Set<String>();
for(Lead l : trigger.new){
    if(l.Country_List_field__c != null){
        countryNames.add(l.Country_List_field__c);
    }
}

// Now we have a set of unique country names we want to verify, time to look them up.
// I plan to build a map of the "match field" -> "full reference object"
Map<String, Country_List_object__c> validCountries = new Map<String, Country_List_object__c>();
for(Country_List_object__c obj : [SELECT Id, Region__c, Country__c FROM Country_List_object__c WHERE Country__c IN :countryNames]){
    validCountries.put(obj.Country__c, obj);
}

// We have all the reference data we need, last loop on the each lead
for(Lead l : trigger.new){
    if(l.Region__c == null && l.Country_List_field__c != null && validCountries.containsKey(l.Country_List_field__c)){
        // found it, do your stuff
        System.debug(l.Country_List_field__c + ' matched ' + validCountries.get(l.Country_List_field__c));
        l.Region__c = validCountries.get(l.Country_List_field__c).Region__c;
    }
}

Couple of notes:

  1. The Country__c field should be unique or the way I'm putting stuff into Map will keep overwriting every time it finds same value.
  2. I'd still point you in the direction mentioned by Daniel Hoest. Validation rule with a VLOOKUP + any workflow that would fire afterwards you're 100% sure has fired only on the Leads that passed the validation.
  3. Depending on whether you need data from your reference object or just need to know whether a match is found - you can use another Set instead of my map. Minor performance benefit I guess. If it's just Region__c -> you could make a Map<String, String> instead of full objects (use map.put(obj.Country__c, obj.Region__c);
  4. Make it a before insert trigger like techtrekker has shown, that way you'll get the database commit for free.
8
  • #2 doesn't apply simple because the intention is to auto-populate REGION__C on the Lead with a value from CountryLists__c custom object.
    – AMM
    Oct 30, 2012 at 20:17
  • I am trying out your code, customizing it now to see what comes of it. It reads properly to me, so I'm hopeful. Thanks. ;-)
    – AMM
    Oct 30, 2012 at 20:40
  • I can imagine management being furious at validation rules on "new lead sources" ;) Sadly this VLOOKUP thing works only for validations (and only against Name field of the reference object). Good luck!
    – eyescream
    Oct 30, 2012 at 20:44
  • Oh.. the day VLOOKUP is more universally usable in Formulas, et al, will be a fine day indeed. One of the three most important Excel functions ever (for what I do) ;-)
    – AMM
    Oct 30, 2012 at 20:48
  • If you don't mind answering: Is it appropriate to post the "final code" here for others to find later, or no? The only way I'd know to do it is to "answer my own question" to make it "look good".
    – AMM
    Oct 30, 2012 at 20:57
3

If you don't have any strong motivations for using a custom object, using a custom setting would make your job even easier. If you declared CountryLists as a custom setting (with Country as the Name) rather than object, you could use this (no soql query needed) to lookup the Region Code and any other values.

(After you've added clarifications then your requirements seem to make it quite a good for the use of a CustomSetting, because you're looking up values.)

Trigger LeadBefore on Lead (before insert, before update){


    For (Lead ld : trigger.new)
    If (ld.CountryList__c != null CountryCustomSetting__c.getInstance(ld.CountyList__c) !=  null){
      ld.Region__c = ContryCustomSetting__.getInstance(ld.CountryList__c).Region__c;
    }

 }
4
  • I think I need to expand my need... doing so now, will mark the expansion clearly...
    – AMM
    Oct 30, 2012 at 19:58
  • I honestly have NO clue what you're doing with the "CountryCustomSetting__c and CountryCustomSetting__". :-( Other than that portion of the code, your code DOES look right, setting ld.region__c based on RegionCode__c from Countrylists. :-/
    – AMM
    Oct 30, 2012 at 20:13
  • I'm trying to motivate you to use a CustomSetting because you don't have to use soql queries to query them and they're available in context. Have a read cloudnow.wordpress.com/2011/04/20/custom-settings-how-and-why Oct 30, 2012 at 20:17
  • I will definitely look at this at some point - thanks for the heads up.
    – AMM
    Oct 30, 2012 at 20:50

You must log in to answer this question.

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