4

I am trying to create a new Account any time a new Contact is created (where the Contact does not have an Account assigned to it) and assign the Contact to the Account via the standard Contact->Account lookup. I have written the following code but the Account does not get assigned.

I added the con.firstName = 'realFirstName'; code at the end to ensure that updates are taking place and that part does work. The Account is created but the Contact -> Account link does not work. What am I missing?

trigger ContactTrigger on Contact(before insert) {

List<Account> newAccounts = new List<Account>();
Map<Contact, Account> conMap = new Map<Contact, Account>();
Map<String, Contact> accNameToContact = new Map<String, Contact>();
List<String> accNames = new List<String>();

//Create and save the new Accounts as needed. Need the ID for the second phase
for(Contact con: Trigger.new){
    //If this is an orphaned Contact, create a new Account for it
    if(con.Account==null){
        String accName = con.LastName+' Household';
        Account acc = new Account(name=accName);

        newAccounts.add(acc);
        accNameToContact.put(accName, con);
        accNames.add(accName);
        conMap.put(con, acc);
    }

}
insert(newAccounts);
List<Account> createdAccounts = [SELECT id, name from Account where name in :accNames ORDER BY id DESC ];

//Can assign the Account here since they have IDs after saving and retrieving them.
for(Account acc: createdAccounts){
    String name = acc.name;

    Contact con = accNameToContact.get(name);
    if(con!=null){
        System.debug('Contact set to this Account ID: '+acc.id);
        con.account = acc; //This assignment does not work.
        con.firstName = 'realFirstName'; //Debug only - this part is saved to the new Contact
        accNameToContact.remove(name);
    }
}    
}
11

You have several problems, nothing major, but enough to keep you from getting to your goal.

con.account = acc;

This assigns the SObject to the relationship field, not the ID field. This only works when upserting by External ID, which you're not doing here. Instead, you need to use the AccountId field.

accNameToContact

This isn't bulk safe. A data loader operation loading 10,000 John Doe contacts is going to link every 200 to the same account.

[SELECT id, name from Account where name in :accNames ORDER BY id DESC ];

You already have the ID values. When you perform an insert DML, the ID value is replaced in-memory, so you don't need to query for those ID values.

if(con.Account==null)

It will always be null. Relationship fields aren't populated automatically, only ID fields are. This is why you can't use, for example, "con.Account.Name" in a trigger before you query it, because the value Account will be null.

All that said, you were on the right track, just going down the wrong path.

Here's a trigger that should work right out of the box.

trigger CreateAccountsForContacts on Contact (before insert) {
    Map<Contact, Account> accounts = new Map<Contact, Account>();
    for(Contact record: Trigger.new) {
        if(record.AccountId == null) {
            accounts.put(record, new Account(Name=record.LastName+' Household'));
        }
    }
    insert accounts.values();
    for(Contact record: Trigger.new) {
        if(record.AccountId == null) {
            record.AccountId = accounts.get(record).Id;
        }
    }
}
1
  • This one is very helpful !!
    – user59759
    Oct 15 '15 at 10:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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