We're loading thousands of records into a custom object (Address__c) over the Bulk API, in parallel mode. It has a Master-Detail relationship with Contact

There's a checkbox field on the object (Primary__c) and some trigger logic on insert which marks the field as true for the first record that is created for a particular contact. The data sent to the API does not set any value and the field level default value is false. The trigger logic is bulkified and is verified by several pairs of eyes to be correct. Theoretically, I'd expect each contact to have exactly one Primary address or no addresses at all. This is true for SOAP API data loads or records created via the UI.

When a day's load completes, I find that sometimes multiple (I've seen only 2 in the records I checked) addresses are set as Primary.

The only explanation and my question is in the title - when 2 batches are running in parallel, do they not see records created by each other through SOQL? I understand, each batch would run its own transaction so the trigger.new is different but I'd expect one of them to commit changes to the DB for the other batches to see.

Edit: Below static method is called from the trigger with trigger.new as parameter.

public static void setPrimaryAddress(List<Address__c> addressList)
    Map<Address__c,String> addressContactMap = new Map<Address__c,String>();
    Map<String,Address__c> contactAddressMap = new Map<String,Address__c>();
    Map<String,Address__c> contactPrimaryAddressMap = new Map<String,Address__c>();

    for(Address__c eachAddress : addressList)
        //Holds the Address & the Associated Contact

    List<Address__c> addrList = [SELECT Id, Address_Type__c, Primary__c, Contact__c FROM Address__c WHERE Contact__c IN: addressContactMap.values() 
                                 AND Primary__c = true]; 
    //List of Address Having Primary as true

    for(Address__c eachAddr : addrList) //Loop through the List of Address & put the contact, Address information in a Map

    for(Address__c anAddr : addressContactMap.keySet()) //Loop through the list of Address that needs to be made as primary
            if(!contactAddressMap.containsKey(anAddr.Contact__c) && !contactPrimaryAddressMap.containsKey(anAddr.Contact__c)) //If the Address is not listed in the PrimaryAddressMap
               anAddr.Primary__c = true;
               contactPrimaryAddressMap.put(anAddr.Contact__c,anAddr); //Add the Primary Address & associated contact in a Map
  • 2
    If they're done in parallel, then one batch won't see the details of another batch that's in process. post your trigger code, sounds like it has some concurrency bugs.
    – superfell
    Commented Dec 29, 2013 at 18:03
  • Before I paste my code, if one batch can't see the records inserted by another, then how can my trigger handle it?
    – LVS
    Commented Dec 30, 2013 at 15:19
  • 1
    you have to serialize access by locking the relevant records (the parent in this case)
    – superfell
    Commented Dec 30, 2013 at 15:55
  • Agree with @superfell, that you're facing rather typical concurrency issue. It would be perfect if you post your code, so as everyone can learn from it! Of course the simplest solution would be changing the Bulk API mode to Serial.
    – endrju
    Commented Dec 31, 2013 at 14:23
  • Appreciate the responses! Will post it by tomorrow..
    – LVS
    Commented Dec 31, 2013 at 17:32

1 Answer 1


I think the problem is in the query for primary addresses. New address records only become visible in SOQL queries in the After-context. If you then do multiple inserts/updates at once they don't see each other's new entries yet. So either you have to lock the parent, as suggested by superfell, or move the logic to the After-context and add an additional Address-update statement for the addresses that should actually be marked as Primary.

I actually prefer the latter since, although it costs an extra update statement, does not impact the user experience and does not contain the risk of locking issues.

  • I'd prefer the latter method too. And I can always contains recursive updates. But how does the 'lock the parent' technique work? I'm interested in knowing
    – LVS
    Commented Jan 2, 2014 at 13:00
  • 1
    Just lock the parent record, without doing anything with it: salesforce.com/us/developer/docs/apexcode/Content/… While there is a lock on the parent record, other parallel processes processing childs of that parent will be halted. Then when the transaction ends, the lock is also relieved. Commented Jan 3, 2014 at 14:11

You must log in to answer this question.

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