7

It seems like something this simple shouldn't require 3 separate maps. I'm querying for the Account and Contact using the Account name pulled from the auto-generated case subject. Any tips are appreciated.

// Called from Case Trigger
public static void beforeInsert(Case[] newCases) {
    Map<String, String> acctNames = new Map<String, String>();
    Map<String, String> caseToAccts = new Map<String, String>();
    Map<String, String> caseToConts = new Map<String, String>();
    for (Case c : newCases) {
        if (c.Origin == 'Email' && c.Subject.contains('Backup Failed:')) {
            acctNames.put(c.Subject.substringBetween('Backup Failed: ',' on'), c.Id);
        }
    }
    for (Account acc : [SELECT Id, Name, (SELECT Id FROM Contacts 
                        WHERE Server_Failure_Contact__c = true) 
                        FROM Account WHERE Name IN :acctNames.values()]) {
        caseToAccts.put(acctNames.get(acc.Name), acc.Id);
        caseToConts.put(acctNames.get(acc.Name), acc.Contacts[0].Id);
    }
    for (Case c : newCases) {
        c.AccountId = caseToAccts.get(c.Id);
        c.ContactId = caseToConts.get(c.Id);
    }
}
3
  • There is a major issue with your trigger, it is a before insert so the c.id is not yet populated and is null.......
    – Eric
    Nov 24, 2014 at 23:09
  • Also I think WHERE Name IN :acctNames.values() should be WHERE Name IN :acctNames.keySet(). Probably better to use the name acctNameToCases for that variable. While you could remove a map, that part of the code is probably clearer the way you have done it. I'd use the type Id instead of String in the maps though where appropriate to make the code a bit clearer. And only do the Account query and following code when acctNames isn't empty.
    – Keith C
    Nov 24, 2014 at 23:11
  • @KeithC Thanks for reminding me that the query can be skipped.
    – sfdcfox
    Nov 24, 2014 at 23:55

1 Answer 1

9

You can reduce the trigger to one map: Map<String, Account>, where String is the account name, and Account is the result of your query and subquery. This reduces your map count to just 1.

// Called from Case Trigger
public static void beforeInsert(Case[] newCases) {
    Map<String, Account> accountMap = new Map<String, Account>();

    for (Case c : newCases) {
        if (c.Origin == 'Email' && c.Subject.contains('Backup Failed:')) {
            accountMap.put(c.Subject.substringBetween('Backup Failed: ',' on'), null);
        }
    }
    if(accountMap.isEmpty()) {
        return;
    }
    for (Account acc : [SELECT Id, Name, (SELECT Id FROM Contacts 
                        WHERE Server_Failure_Contact__c = true) 
                        FROM Account WHERE Name IN :acctNames.keySet()]) {
        accountMap.put(acc.Name, acc);
    }
    for (Case c : newCases) {
        String acctName = c.Subject.substringBetween('Backup Failed: ',' on');
        if(accountMap.get(acctName) != null) {
            c.AccountId = accountMap.get(acctName).Id;
            if(!accountMap.get(acctName).Contacts.IsEmpty()) {
                c.ContactId = accountMap.get(acctName).Contacts[0].Id;
            }
        }
    }
}

Some other general observations:

"Backup Failed: Meal on Wheels on 12/27/2013" will return "Meal" instead of "Meal on Wheels". I'm pretty sure this would be a rare situation, but you might need to account for that. I'd suggest using a Pattern/Matcher class combination to reduce false positives.

2
  • Nice. Still needs acctNames.values() => accountMap.keySet().
    – Keith C
    Nov 25, 2014 at 0:02
  • @KeithC And that's what I get for copy-pasting!
    – sfdcfox
    Nov 25, 2014 at 1:25

You must log in to answer this question.

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