Apex ListException – Handling Before Insert or Upsert with Identically Equal Elements

I had the following exception thrown at me when trying to process more than one selected records via a custom button in the list view.

enter image description here

Class Code

global class MerchandiseInventoryClass {


   webservice static void ConverttoInventory(String[] merchandise_id)
   {
       //Convert Merchandise collection into Inventory Collection...

       Merchandise__c[] merchandise_collection = [SELECT ID,Author__c,Book_Title__c,Edition__c,Publisher__c,Total_Merchandise_QtyTotal_Qty__c,Status__c FROM Merchandise__c WHERE ID = :merchandise_id];


       Inventory__c i = new Inventory__c(); //Line 1
       List<Inventory__c> newInventory = new List<Inventory__c>();
       for(Merchandise__c m : merchandise_collection )
       {
           if(m.Status__c !='Fully Converted')
           {
           i.Author__c = m.Author__c ;
           i.Book_Title__c = m.Book_Title__c;
           i.Edition__c = m.Edition__c;
           i.Publisher__c = m.Publisher__c;
           i.Qty_Available__c = m.Total_Merchandise_QtyTotal_Qty__c;
           i.Merchandise__c = m.Id;
           m.Uninventoried_Qty__c = 0;
           m.Status__c = 'Fully Converted';
           newInventory.add(i);
           }
       }
       insert newInventory;
       update merchandise_collection;
   }

}

By moving the Line 1 to within the for loop solved the issue for me.

Thanks to this post (refer the Best Answer in that post)

https://developer.salesforce.com/forums/ForumsMain?id=906F00000008vFjIAI

What puzzles me is that WHY i have to instantiate "i" for every iteration within the loop.

Why the list collection ("newInventory") is complaining that are duplicate elements and why should it even confuse in the first place when I am performing an "insert" even ?

Best Answer

This line of your code:

Inventory__c i = new Inventory__c();

creates a block of memory that is big enough to hold all the fields of the inventory object and your variable i holds a reference to that memory (its address). As the loop runs, the code changes the values within that block of memory, then this line:

newInventory.add(i);

adds the same reference value to the list multiple times.

Salesforce made the design choice to flag this condition of multiple identical references by throwing an exception. If they had not, the code would have inserted multiple copies of the object with the fields set to the values of the last iteration round the loop which is not useful and is a harder to detect bug.

Moving the new inside the loop yields the correct code with a separate block of memory for each inventory object and so independent values for the fields.

Related Topic