What is a use case where one would use an SObject as a Map key?

In Dan Appleman’s book Advanced Apex Programming, he explains how using SObjects as Map keys (i.e. Map<SObject, *value*>) is supported but it’s poor practice, since the key is actually determined by a hash of all the fields on that SObject key – so if there’s a change to even just one field, the key is changed.

My question is – why is this supported? I’m having trouble thinking of even one case where using this type of collection would be desired? The point of using a Map is to be able to retrieve data based on semantic-trivial, immutable data (such as IDs)…

Answer

I use SObject as a key when I want to use a composite key. For example, say I want to find duplicates based on first name, last name, and email. I might loop through a list of contacts, and create a contact that matches the keys I’m using:

Incoming.put(new Contact(FirstName= record.FirstName, LastName= record.LastName, Email= record.Email), record);

Then, when I query the database on those three fields, I can quickly look up the new records, again by constructing a key from an SObject.

This is more reliable than concatenating strings and hoping that it is unique enough that it won’t grab false positives.


Example:

trigger matchDupes on Lead (before insert, before update) {
    Map<Lead, Lead> leads = new Map<Lead, Lead>();
    Set<String> company = new Set<String>(), email = new Set<String>();

    // Match duplicates in this transaction
    for(Lead record: Trigger.new) {
        Lead key = new Lead(Company=record.Company, Email=record.Email);
        if(leads.containsKey(key)) {
            record.addError('This lead matches a duplicate lead.');
            continue;
        }
        company.add(record.company);
        email.add(record.email);
        leads.put(key, record);
    }
    // Match duplicates in the database
    for(Lead record: [SELECT Email, Company from Lead WHERE Company in :company and Email IN :email]) {
        Lead key = new Lead(Company=record.Company, Email=record.Email),
             dupLead = leads.remove(key);
        if(dupLead != null) {
           dupLead.addError('This lead matches a duplicate lead.');
        }
    }
}

Note that I could use an arbitrary number of fields (in most cases). There’s several considerations, such as case sensitivity, not included here. I’d recommend always trying to convert to a common case when putting into/out of the map, but generally speaking this technique works well.

Attribution
Source : Link , Question Author : Brian Mansfield , Answer Author : sfdcfox

Leave a Comment