Create Parent and Child Records in One Insert Call

135 Views

If you’re anything like me, creating parent and child records in Apex is something that has to be done on a pretty regular basis. This blog post is one I’ve had on the list for a while, but it came upon the discussion boards on March 2012 so it seemed like as good a time as any to write it up properly.

The simplest way to achieve this is to insert the parent, then set the lookup relationship id on the child to the parent record id, as follows:

Account acc=new Account(Name='Blog Acc1');
insert acc;
 
Contact cont=new Contact(FirstName='Bob', LastName='Buzzard', AccountId=acc.id);
insert cont;

the downside to this approach is that it is unlikely to scale.  If I need to insert a large number of accounts and contacts, I’ll have to manage the relationships myself in some way – probably using wrapper classes to combine an account and its list of contacts, with multiple iterations to insert the accounts, then populate the lookup fields.  All in all quite a lot of code.

The next avenue I explored was setting the child relationship field to the parent record:

Account acc=new Account(Name='Blog Acc2');
insert acc;
 
Contact cont=new Contact(FirstName='Bob', LastName='Buzzard', Account=acc);
insert cont;

No dice on this I’m afraid – even though I’ve inserted the parent account first, the child contact is stored without a parent account.

One of the techniques that I came across while studying for the Technical Architect Certification was to specify the parent object via an external id.  So I created an external id field on my account named Master_Id__c and inserted an account:

Account acc=new Account(Name='Blog Acc3', Master_Id__c='Blog Acc3');
insert acc;

Once the account is in place, I can instantiate the parent record based on the external id and set the relationship field:

Account acc=new Account(Master_Id__c='Blog Acc3');
Contact cont=new Contact(FirstName='Bob', LastName='Buzzard', Account=acc);
insert cont;

Looking better, as I don’t have to set ids, but I’m still inserting the parent first and then the child. Perhaps its possible to instantiate a new account and contact and then insert them later:

Account acc=new Account(Name='Blog Acc 4', Master_Id__c='Blog Acc 4');
Contact cont=new Contact(FirstName='Bob', LastName='Buzzard', Account=acc);
insert acc;
insert cont;

Once again, no dice. The same result as the second attempt – the account and contact are inserted, but the relationship is lost. Given that there’s very little difference between this and the last attempt, it looks like its the name that is causing the problem. After trying a few permutations, the following code confirmed that this is the case:

Account acc=new Account(Name='Blog Acc 6', Master_Id__c='Blog Acc 6');
insert acc;
 
Contact cont=new Contact(FirstName='Bob', LastName='Buzzard', Account=new Account(Name='Blog Acc 6', Master_Id__c='Blog Acc 6'));
insert cont;

This throws the following exception – System.DmlException: Insert failed. First exception on row 0; first error: INVALID_FIELD, More than 1 field provided in an external foreign key reference in entity: Account: [].
 I’ve no idea why this exception isn’t thrown when I specify a previously instantiated account rather than instantiating as part of the contact record, but there it is.   Given this error message, it seemed possible to create a contact and identify the account by Name, but that didn’t work either – a similar exception complaining that Name isn’t an external id or indexed field.

 This did guide me to the preferred solution though – simply instantiating a new account as part of the contact and only specifying the external id:

Account acc=new Account(Name='Blog Acc 7', Master_Id__c='Blog Acc 7');
insert acc;
 
Contact cont=new Contact(FirstName='Bob', LastName='Buzzard', Account=new Account(Master_Id__c='Blog Acc 7'));
insert cont;

Looking a lot better, but there are still two insert statements – luckily insert statements can take a list of generic sobjects to insert, so I can insert both objects in one go. As long as the parent record is inserted first, everything works as expected:

Account acc=new Account(Name='Blog Acc 8', Master_Id__c='Blog Acc 8');
Contact cont=new Contact(FirstName='Bob', LastName='Buzzard', Account=new Account(Master_Id__c='Blog Acc 8'));
 
insert new List<Sobject>{acc, cont};

Inserting the Child FIRST and Parent afterward, like



Account acc=new Account(Name='Blog Acc 8', Master_Id__c='Blog Acc 8');
Contact cont=new Contact(FirstName='Bob', LastName='Buzzard', Account=new Account(Master_Id__c='Blog Acc 8'));
 
insert new List<Sobject>{cont, acc};

It will give you an error:

INVALID_FIELD – Foreign key external ID: Blog Acc 7 not found for field Master_Id__c on Account.

To Resolve it, make sure to have Parent Object in a list before the child.

Leave a Comment