4

I've been working as a developer for about 3 months, so my terminology may be off.

I'm trying to add records to a custom object.

As the new record information is added to a List, the previous additions in the list are changed to the last addition. Inserting the List causes "FATAL_ERROR System.ListException: Before Insert or Upsert list must not have two identically equal elements". All of the list elements are the same as the last addition.

Can someone tell this newbie what he's doing wrong?

    trigger BD_Lead_Trigger on Lead (before insert, before update) {

    List<NFP_Lead_Account__C> NewLeadAccounts = new List<NFP_Lead_Account__C>();
    NFP_Lead_Account__C NewRecord = new NFP_Lead_Account__C();

    Map<String, Id> OldLeadAccounts = new Map<String, Id>();

// Put the lead accounts into a map before entering the Trigger loop
    for(NFP_Lead_Account__c la : [SELECT BD_Account_Name__c, Id FROM NFP_Lead_Account__c]){
    OldLeadAccounts.put(la.BD_Account_Name__c, la.Id);
    }

    for(Lead newLead : Trigger.new){

// Is this a BD Lead?        
        If(newLead.RecordTypeId == Schema.SObjectType.Lead.getRecordTypeInfosByName().get('BD Lead').getRecordTypeId()){ // Yes

System.Debug('NewLead.Company : ' + NewLead.Company);
System.Debug('OldLeadAccounts.get(NewLead.Company) : ' + OldLeadAccounts.get(NewLead.Company));

// Does this BD Lead's company exist?
            If(OldLeadAccounts.get(NewLead.Company) == null){ // No
                NewRecord.BD_Account_Name__c = NewLead.Company;
                NewLeadAccounts.add(NewRecord);
System.Debug('Watch this grow -- NewLeadAccounts : ' + NewLeadAccounts);
                OldLeadAccounts.put(NewLead.Company, 'a1E2F0000000000000');
            }
        }
    }

// Insert the new Lead Accounts / Companies / Organizations 
System.Debug('NewLeadAccounts : ' + NewLeadAccounts);
    insert NewLeadAccounts;

// Clear the Lead account map, and put in the new lead accounts before entering the Trigger loop
    OldLeadAccounts.clear();
    for(NFP_Lead_Account__c la : [SELECT BD_Account_Name__c, Id FROM NFP_Lead_Account__c]){
        OldLeadAccounts.put(la.BD_Account_Name__c, la.Id);
    }

// Add the new lead account ids to the new BD Leads
    for(Lead NewLead : Trigger.new){
        NewLead.BD_Lead_Account__c = OldLeadAccounts.get(NewLead.Company);    
    }
}

Here is USER_DEBUG from the Execution Log: Check out "Watch this grow --".

enter image description here

2 Answers 2

5

You're doing things in a kinda funky way, and that's leading to your issues.

A list that holds SObjects (such as your List<NFP_Lead_Account>) will hold references to the SObject instance.

So, if you do something like this

List<SObject> myList = new List<SObject>();
MyObject__c myRec  = new MyObject__c();

myList.add(myRec);
myList.add(myRec);

Then you're storing the same reference in the list, twice. Alter data for one of the references, and you alter the data for all of them.

The thing that you probably want to do to fix this is to create a new instance of NFP_Lead_Account in each iteration of your loop like this

for(Lead newLead : Trigger.new){
    // This is the important line
    newRecord = new NFP_Lead_Account();

    // Is this a BD Lead?        
    If(newLead.RecordTypeId == Schema.SObjectType.Lead.getRecordTypeInfosByName().get('BD Lead').getRecordTypeId()){ // Yes

        System.Debug('NewLead.Company : ' + NewLead.Company);
        System.Debug('OldLeadAccounts.get(NewLead.Company) : ' + OldLeadAccounts.get(NewLead.Company));

            // Does this BD Lead's company exist?
            If(OldLeadAccounts.get(NewLead.Company) == null){ // No
                NewRecord.BD_Account_Name__c = NewLead.Company;
                NewLeadAccounts.add(NewRecord);
                System.Debug('Watch this grow -- NewLeadAccounts : ' + NewLeadAccounts);
                OldLeadAccounts.put(NewLead.Company, 'a1E2F0000000000000');
            }
        }
    }

Doing this ensures that you have a distinct instance to work with in each iteration of your loop, which means you won't be overwriting previous values.

4
  • 1
    Thanks for your quick and clear solution Derek! My coding is funky, because apex and Salesforce are still working their way into my understanding. You just helped me clear out a bit of that funk.
    – Ptochos
    Jun 29, 2018 at 16:13
  • Why not going for a Set instead of a map and a condition ?? Jun 29, 2018 at 16:16
  • @Answers_Seeker I don't know, I didn't digest OP's code that far. My main concern was addressing the error mentioned in the question.
    – Derek F
    Jun 29, 2018 at 16:20
  • To your experienced eyes, My code should look like a 3 month old wrote it. I needed to lookup the company name to get it's Id number so it can be used as a Lookup(Lead Account). Doing a SOQL lookup in the trigger loop works for a single manual entry, but it hit the limits with the Import Wizard. I found the solution to use Map to lookup an Id with a string.
    – Ptochos
    Jun 29, 2018 at 17:34
4

So to give a complete overview of the error and the problem at hand, the error coming back is telling you that the list contains multiple references to the same object so you're inserting a list of the same object. Please see here for reference to Collections in Apex: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_collections.htm

In this case Lists are allowed to have duplicates while Sets don't allow for duplicate entries.

For this specific problem:

You are indeed inserting the same NFP_Lead_Account__C record once per-loop in that for loop defined as for(Lead newLead : Trigger.new). So when you update that NFP_Lead_Account__c object, you are updating the same instance of the object that are in the other indexes of the list because they are the same object and then you add another reference to that same object into the list.

I am assuming that you are trying to create a new instance of the NFP_Lead_Account__c Object for each Lead that you are inserting. In this case what you need to do is move your instantiation of the object to be inside of the for-loop so that you are making a new object for each Lead.

See Here:

for(Lead newLead : Trigger.new){
    NFP_Lead_Account__C NewRecord = new NFP_Lead_Account__C();

    //do your logic with a new NFP_Lead_Account__c for each Lead

}

You must log in to answer this question.

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