+ Start a Discussion
Subodh shuklaSubodh shukla 

Duplicate Id Error in Test Class

Hi all,
I have a below trigger to update Invoice
trigger Updateinvoicestatus on Line_Item__c (after insert,after update) {
  
    Invoice_Statement__c[] I = new list<Invoice_Statement__c>();
    for(Line_Item__c ln: trigger.new)  {     
        Invoice_Statement__c INV= new Invoice_Statement__c(id = ln.Invoice_Statement__c);
        List<Line_Item__c>Lnv=[select id,Name from Line_Item__c where Invoice_statement__c =:INV.id];
        if(Lnv.size()==5){
            INV.status__c='Closed';
             I.add(INV);
             }
            if(Lnv.size()==6){
            ln.addError('You cant add more then five item');
           
        }
               
    }  
   Update I; 
     }
But in test class for the above trigger is giving following error
System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, Updateinvoicestatus: execution of AfterInsert
caused by: System.ListException: Duplicate id in list: a0228000005aT8UAAU
Trigger.Updateinvoicestatus: line 17, column 1: []
here is my test class
@istest
public class TestUpadateInvcStatus {
    public  static testmethod void updatetest(){
        Merchandise__c [] M = new list<Merchandise__c> {
            new merchandise__c (Name = 'test 1', Description__c = 'test', Price__c = 100, Total_Inventory__c = 1000),
            new merchandise__c (Name = 'test 2', Description__c = 'test', Price__c = 100, Total_Inventory__c = 1000),
            new merchandise__c (Name = 'test 3', Description__c = 'test', Price__c = 100, Total_Inventory__c = 1000),
            new merchandise__c (Name = 'test 4', Description__c = 'test', Price__c = 100, Total_Inventory__c = 1000),
            new merchandise__c (Name = 'test 5', Description__c = 'test', Price__c = 100, Total_Inventory__c = 1000)
                };
        Insert m;
        
        Invoice_Statement__c inv = new Invoice_Statement__c (Status__c = 'Open');
        insert inv;
        
        Line_Item__c [] li = New List<Line_Item__c>{ 
            new line_Item__c(Name = '1', Merchandise__c = m[0].id, Invoice_Statement__c = inv.id ),
                new line_Item__c(Name = '2', Merchandise__c = m[1].id, Invoice_Statement__c = inv.id ),
                new line_Item__c(Name = '3', Merchandise__c = m[2].id, Invoice_Statement__c = inv.id ),
                new line_Item__c(Name = '3', Merchandise__c = m[4].id, Invoice_Statement__c = inv.id ),
                new line_Item__c(Name = '3', Merchandise__c = m[4].id, Invoice_Statement__c = inv.id )
                
                };
         
                 Insert li;   
                  Line_item__c itm = new line_item__c(Name = '4', Merchandise__c = m[4].id, Invoice_Statement__c = inv.id);
        			Database.SaveResult sa = Database.insert(itm, false);
                    System.assert(!sa.isSuccess()); 
                    
                        
    }
}
It is giving 90% code coverage.
Pls give sugesstion Why I am getting this error?
 
Best Answer chosen by Subodh shukla
Alexander TsitsuraAlexander Tsitsura
I recomened you to avoid soql for loop.

You can query all needed records before for.
 
Set<Id> invIds = new Set<Id>();
for (Line_Item__c li : Trigger.New) {
  invIds.add(li.Invoice_Statement__c);
}

Map<Id, Line_Item__c[]> iMap = new Map<Id, Line_Item__c[]>();
for (Line_Item__c i : [SELECT ID, Name FROM Line_Item__c WHERE Invoice_Statement__c IN :invIds]) {
  if (!iMap.containsKey(i.Invoice_Statement__c)) {
    iMap.put(i.Invoice_Statement__c, new Line_Item__c[] {});
  }

  iMap.get(i.Invoice_Statement__c).add(i);
}

for (Line_Item__c ln : Trigger.new) {
  List<Line_Item__c> Lnv = iMap.get(ln.Invoice_Statement__C);
  // logic here
}

Thanks,
Alex

All Answers

Alexander TsitsuraAlexander Tsitsura
Hi Subodh,

Your list I contains dubplicate records, for avoid it try use set instead of list.


try code below
trigger Updateinvoicestatus on Line_Item__c (after insert,after update) {
  
    Set<Invoice_Statement__c> I = new Set<Invoice_Statement__c>();
    for(Line_Item__c ln: trigger.new)  {     
        Invoice_Statement__c INV= new Invoice_Statement__c(id = ln.Invoice_Statement__c);
        List<Line_Item__c>Lnv=[select id,Name from Line_Item__c where Invoice_statement__c =:INV.id];
        if(Lnv.size()==5){
            INV.status__c='Closed';
             I.add(INV);
             }
            if(Lnv.size()==6){
            ln.addError('You cant add more then five item');
           
        }
               
    }  
   Update new List<Invoice_Statement__c>(I); 
     }
As a common practice, if your question is answered, please choose 1 best answer. 
But you can give every answer a thumb up if that answer is helpful to you.

Thanks,
Alex
 
Alexander TsitsuraAlexander Tsitsura
I recomened you to avoid soql for loop.

You can query all needed records before for.
 
Set<Id> invIds = new Set<Id>();
for (Line_Item__c li : Trigger.New) {
  invIds.add(li.Invoice_Statement__c);
}

Map<Id, Line_Item__c[]> iMap = new Map<Id, Line_Item__c[]>();
for (Line_Item__c i : [SELECT ID, Name FROM Line_Item__c WHERE Invoice_Statement__c IN :invIds]) {
  if (!iMap.containsKey(i.Invoice_Statement__c)) {
    iMap.put(i.Invoice_Statement__c, new Line_Item__c[] {});
  }

  iMap.get(i.Invoice_Statement__c).add(i);
}

for (Line_Item__c ln : Trigger.new) {
  List<Line_Item__c> Lnv = iMap.get(ln.Invoice_Statement__C);
  // logic here
}

Thanks,
Alex
This was selected as the best answer