I have a button that needs to make several webservice callouts and then use the resulting data to upsert a collection of OpportunityLineItems.

For each OpportuntiyLineItem there is also a collection of custom sObjects that also need to be upserted. Each of these custom objects has a field that contains the parent OpportunityLineItem id.

Due to the callouts I'm building up a list of OpportuntiyLineItems and a separate structure that maps from the OpportuntiyLineItem to the child custom sObjects.

The challenge in the separate structure is how to track the relationship between the OLIs and related custom sObjects when the OLI may not have an ID yet. A Map from the OpportunityLineItem.Id to a list of custom objects works fine for existing OLI, but doesn't help with new OLIs.

These isn't currently another unique field I can use to identify the OLI.

The core steps involved:

  1. SOQL to find the existing OLIs
  2. Web service callout to pull the data to update/create OLIs with
  3. Create a list of OLIs, either update an existing found OLI, or add a new OLI.
  4. SOQL to find the existing custom objects for existing OLIs
  5. Second web service callout to pull the data to update/create the child sObject
  6. Create a list of secondary sObjects to update/create for each OLI.
    Here I need to maintain a relationship with the OLI to set the custom secondary object after the OLI has been inserted.
  7. No more web service callouts can occur after the first upsert.
  8. Upsert List of OLIs
  9. For each OLI, set the OLI Id on each custom sObject.
  10. Combine all the custom sObject lists and Upsert complete list

Example data:

  • New OLI 1
    • New Custom sObject 4
    • New Custom sObject 5
  • New OLI 2
    • New Custom sObject 6
  • New OLI 3
    • New Custom sObject 7
    • New Custom sObject 8

With this data the first upsert would insert OLIs 1, 2, and 3. I then need to set the OLI.Id field:

  • on custom sObjects 4 and 5 to the Id of OLI 1
  • on custom sObject 6 to the Id of OLI 2
  • on custom sObjects 7 and 8 to the Id of OLI 3

I'd initially tried using a Map keyed with the OpportunityLineItem, but that failed badly when any of the OLI fields were changed after it was added to the Map. The hash of the sObject changes and it can no longer be found in the Map keyset.

How can I keep track of the new OpportunityLineItems before and after insert so I can then insert related records?

2 Answers 2


I had several situations like that and sadly thee solution was to stop thinking object oriented. You youngsters with your pretty map objects & relational queries ;)

Use List<OpportunityLineItem> and List<List<Object__c>> and match them by index (5th OLI's Id will be eventually used in upsert of 5th list of objects).

Do your magic, end with flattening of the 2D list (addAll() in a loop), fire? It was for me no trickier to maintain relationship this way than to maintain Map<parent, List<kids>>, especially in terms of initial population with subquery.

Since OLIs don't allow relationships / subqueries you might have to help yourself extra with Map<Id, Integer> (id => array index)...

  • Back in my day we had to malloc and free memory in C or walk 15 miles in the snow to write GOTOs in BASIC on an Apple IIe. Still, maintaining the object references in a list is good idea as I won't need to modify the schema to handle it. I do feel compelled to wrap these lists and the methods for manipulating them in another object though. Commented Jun 6, 2013 at 20:31

I'm not sure if it works with Upsert, but I know you can build references using external ids and it'll work with Insert. So imagine you have an object with a self-reference Lookup back to that same object type called Related_Object__c, as well as a custom unique External_Id__c field. If I construct record 1 like:

Object__c myObj1 = new Object(External_Id__c = '123456');
Object__c myObj2 = new Object(Related_Object__c = myObj2.External_Id__c);

I can then insert myObj1, followed by inserting myObj2, and it'll build that relationship from myObj2 to myObj1.

  • That would be a good option, except I can't have a lookup relationship to OLI. You were right about how much fun that limitation creates :) Commented Jun 6, 2013 at 0:07
  • Oooh. What about building an OLI External Id, stuffing it into a plain text field on the child, and then in the child trigger go find the related OLI an sets it's actual Id value? Guess that presumes you put the OLIs in first... Commented Jun 6, 2013 at 2:27

You must log in to answer this question.

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