I have a batch apex that runs thru some attachments of a custom "Job" object that I made.

There are 5 CSV files attached to this Job object, which I parse & create Salesforce records from.

Now the data creation works great, but the problem is that some records relate to other records, and I need to be sure that the parents are created first, and then the childs later.

For example, I have to read the Accounts in first, and then the Contacts, because the contacts are obviously related to the accounts.

Sadly, the batch apex runs asynchronously, and I cannot force it to start & finish with a CSV file first, before getting onto the second file...

Any way to force some kind of order in this code?

I tried chaining (via the finish method of the class), but it's still not working out how it should.

Some code examples are below.

My main EXECUTE function, where I do the CSV parsing and importing:

global void execute(Database.BatchableContext context, List<SObject> records) {

    //get Accounts
    if (TargetParam == 'Accounts') {
        Attachment accountsAttachment = getAttachmentByType('accounts', records);
        if (accountsAttachment != null) {
            List<List<String>> accountsCsvRecords = parseCSV.parseCSV(accountsAttachment.Body.toString(), true);
            import (accountsCsvRecords, 'Account');

    //get Contacts
    if (TargetParam == 'Contacts') {
        Attachment contactsAttachment = getAttachmentByType('contacts', records);
        if (contactsAttachment != null) {
            List<List<String>> contactsCsvRecords = parseCSV.parseCSV(contactsAttachment.Body.toString(), true);
            import (contactsCsvRecords, 'Contact');


Here's my FINISH method where I try to daisy-chain the calls together:

global void finish(Database.BatchableContext context) {
    if (TargetParam == 'Accounts') {
        System.debug('TESTING -- Finished with Accounts. Now onto the Contacts...');

        //call batch apex on Contacts
        DataLoaderImportCSVJob gdl = new DataLoaderImportCSVJob(job.Id, job, 'Contacts');
    if (TargetParam == 'Contacts') {
        System.debug('TESTING -- Finished with Contacts. Now onto the License Headers...');

        //call batch apex on License Headers
        DataLoaderImportCSVJob gdl = new DataLoaderImportCSVJob(job.Id, job, 'License Headers');

And here's my GetDocumentQuery method, where I select the attachments:

global String getDocumentQuery() {
    return 'SELECT Id, Name, Body FROM Attachment WHERE ParentId =:DataLoaderJobId order by Name asc';

Maybe there's a clever way of doing this?

  • Not an answer to your question, but an observation: don't use "global" unless you have to. And that means to expose the class/methods in one namespace to another namespace or between a namespace and no namespace. Basically only required when using packages and exposing code from the package, or from outside a package to the package. See the documentation for details.
    – Phil W
    Dec 5 '19 at 9:00
  • Thank you Phil, I will take that in mind!
    – Laureant
    Dec 5 '19 at 9:11

This site is temporarily in read only mode and not accepting new answers.

Browse other questions tagged .