I have a customer's org that is throwing an error once in a while.
ELTON.After_Update_Contact_Values: execution of AfterUpdate
caused by: System.ListException: Duplicate id in list: a36a00000009IEUAA2
Trigger.ELTON.After_Update_Contact_Values: line 65, column 1
I can't actually duplicate the problem but I have e-mails showing it happens in the customer org every few days or so.
I think I know the answer... it is to stop using lists to record which records need to be updated and convert to using maps to ensure a given Equipment__c.Id never gets onto the update list twice.
My problem is maps confuse me (the first step is admitting you have a problem).
I feel really guilty asking this (I am getting y'all to do my work for me) but I think it would be invaluable for me to get this information... perhaps reducing my confusion when it comes to maps...
Could someone be so kind as to take my trigger code below and show me how you would convert it so that lstEQ2 and lstEQ3 are replaced with maps ?
trigger After_Update_Contact_Values on Contact (after update)
{
List<ELTON__Equipment__c> lstEQ=new List<ELTON__Equipment__c>();
List<ELTON__Equipment__c> lstEQ1=new List<ELTON__Equipment__c>();
List<ELTON__Equipment__c> lstEQ2=new List<ELTON__Equipment__c>();
List<ELTON__Equipment__c> lstEQ3=new List<ELTON__Equipment__c>();
lstEQ = [select id,ELTON__Assigned_Contact__c,ELTON__Assigned_Name__c from ELTON__Equipment__c
where ELTON__Assigned_Contact__c=:Trigger.New];
lstEQ1 = [select id,ELTON__Loan_Contact__c,ELTON__Loan_Name__c from ELTON__Equipment__c
where ELTON__Loan_Contact__c=:Trigger.New];
for(Contact Con:Trigger.new)
{
if((Con.MailingCity != trigger.oldMap.get(Con.Id).MailingCity) || (Con.MailingCountry != trigger.oldMap.get(Con.Id).MailingCountry) ||
(Con.MailingPostalCode != trigger.oldMap.get(Con.Id).MailingPostalCode) || (Con.MobilePhone != trigger.oldMap.get(Con.Id).MobilePhone) ||
(Con.MailingState != trigger.oldMap.get(Con.Id).MailingState) || (Con.MailingStreet != trigger.oldMap.get(Con.Id).MailingStreet) ||
(Con.Name != trigger.oldMap.get(Con.Id).Name) || (Con.Phone != trigger.oldMap.get(Con.Id).Phone) ||
(Con.Email != trigger.oldMap.get(Con.Id).Email) || (Con.OtherPhone != trigger.oldMap.get(Con.Id).OtherPhone) ||
(Con.FirstName != trigger.oldMap.get(Con.Id).FirstName) || (Con.LastName != trigger.oldMap.get(Con.Id).LastName))
{
for(ELTON__Equipment__c objEquipment:lstEQ)
{
ObjEquipment.ELTON__Assigned_Address__c = Con.MailingStreet;
// ObjEquipment.ELTON__Assigned_Address__c = (ObjEquipment.ELTON__Assigned_Address__c).replace('null','');
ObjEquipment.ELTON__Assigned_City__c = Con.MailingCity;
ObjEquipment.ELTON__Assigned_Country__c = Con.MailingCountry;
ObjEquipment.ELTON__Assigned_Name__c = Con.FirstName + ' ' + Con.LastName;
ObjEquipment.ELTON__Assigned_State_Province__c = Con.MailingState;
ObjEquipment.ELTON__Assigned_Zip_Postal_Code__c = Con.MailingPostalCode;
ObjEquipment.ELTON__Assigned_Phone__c = Con.Phone;
ObjEquipment.ELTON__Assigned_Other_Phone__c = Con.OtherPhone;
ObjEquipment.ELTON__Assigned_Email__c = Con.Email;
ObjEquipment.ELTON__Assigned_Mobile__c = Con.MobilePhone;
lstEQ2.add(ObjEquipment);
}
for(ELTON__Equipment__c objEquipment:lstEQ1)
{
ObjEquipment.ELTON__Loan_Address__c = Con.MailingStreet;
// ObjEquipment.ELTON__Loan_Address__c = (ObjEquipment.ELTON__Loan_Address__c).replace('null','');
ObjEquipment.ELTON__Loan_City__c = Con.MailingCity;
ObjEquipment.ELTON__Loan_Country__c = Con.MailingCountry;
ObjEquipment.ELTON__Loan_Name__c = Con.FirstName + ' ' + Con.LastName;
ObjEquipment.ELTON__Loan_State_Province__c = Con.MailingState;
ObjEquipment.ELTON__Loan_Zip_Postal_Code__c = Con.MailingPostalCode;
ObjEquipment.ELTON__Loan_Phone__c = Con.Phone;
ObjEquipment.ELTON__Loan_Other_Phone__c = Con.OtherPhone;
ObjEquipment.ELTON__Loan_Email__c = Con.Email;
ObjEquipment.ELTON__Loan_Mobile__c = Con.MobilePhone;
lstEQ3.add(ObjEquipment);
}
}
}
if(lstEQ2.size()>0)
{
update lstEQ2;
}
if(lstEQ3.size()>0)
{
update lstEQ3;
}
}
UPDATE Jan 15/2013 - Further to Ben's Answer and my comment to that answer
Below is the trigger modified to use a single map. My idea is that the map created at the top contains unique combinations of Contact ID and Equipment ID whether the Equipment is assigned, loaned or both.
My problem now is my continuing confusion with the syntax of maps. The error I am getting is:
Error: Compile Error: Invalid initial value type SOBJECT:ELTON__Equipment__c for LIST<ELTON__Equipment__c> at line 15 column 54
Line 15 is:
mapEQ.put(eq.ELTON__Assigned_Contact__c, new List<ELTON__Equipment__c>(eq));
Any ideas??
trigger After_Update_Contact_Values on Contact (after update)
{
List<ELTON__Equipment__c> lstEQ2=new List<ELTON__Equipment__c>();
Map<Id, List<ELTON__Equipment__c>> mapEQ = new Map<Id, List<ELTON__Equipment__c>>();
for (ELTON__Equipment__c eq : [select id, ELTON__Assigned_Contact__c, ELTON__Loan_Contact__c
from ELTON__Equipment__c
where
ELTON__Assigned_Contact__c=:Trigger.New
OR ELTON__Loan_Contact__c=:Trigger.New])
{
if (mapEQ.containsKey(eq.ELTON__Assigned_Contact__c) == false)
{
mapEQ.put(eq.ELTON__Assigned_Contact__c, new List<ELTON__Equipment__c>(eq));
}
if (mapEQ.containsKey(eq.ELTON__Loan_Contact__c) == false)
{
mapEQ.put(eq.ELTON__Loan_Contact__c, new List<ELTON__Equipment__c>(eq));
}
}
for(Contact Con:Trigger.new)
{
if((Con.MailingCity != trigger.oldMap.get(Con.Id).MailingCity) || (Con.MailingCountry != trigger.oldMap.get(Con.Id).MailingCountry) ||
(Con.MailingPostalCode != trigger.oldMap.get(Con.Id).MailingPostalCode) || (Con.MobilePhone != trigger.oldMap.get(Con.Id).MobilePhone) ||
(Con.MailingState != trigger.oldMap.get(Con.Id).MailingState) || (Con.MailingStreet != trigger.oldMap.get(Con.Id).MailingStreet) ||
(Con.Name != trigger.oldMap.get(Con.Id).Name) || (Con.Phone != trigger.oldMap.get(Con.Id).Phone) ||
(Con.Email != trigger.oldMap.get(Con.Id).Email) || (Con.OtherPhone != trigger.oldMap.get(Con.Id).OtherPhone) ||
(Con.FirstName != trigger.oldMap.get(Con.Id).FirstName) || (Con.LastName != trigger.oldMap.get(Con.Id).LastName))
{
if (mapEQ.containsKey(Con.Id))
{
for (ELTON__Equipment__c objEquipment : mapEQ.get(Con.Id))
{
if(ObjEquipment.ELTON__Assigned__Contact == Con.Id)
{
ObjEquipment.ELTON__Assigned_Address__c = Con.MailingStreet;
ObjEquipment.ELTON__Assigned_City__c = Con.MailingCity;
ObjEquipment.ELTON__Assigned_Country__c = Con.MailingCountry;
ObjEquipment.ELTON__Assigned_Name__c = Con.FirstName + ' ' + Con.LastName;
ObjEquipment.ELTON__Assigned_State_Province__c = Con.MailingState;
ObjEquipment.ELTON__Assigned_Zip_Postal_Code__c = Con.MailingPostalCode;
ObjEquipment.ELTON__Assigned_Phone__c = Con.Phone;
ObjEquipment.ELTON__Assigned_Other_Phone__c = Con.OtherPhone;
ObjEquipment.ELTON__Assigned_Email__c = Con.Email;
ObjEquipment.ELTON__Assigned_Mobile__c = Con.MobilePhone;
}
else
{
// assumes this equipment is on the list because it's a loan
ObjEquipment.ELTON__Loan_Address__c = Con.MailingStreet;
ObjEquipment.ELTON__Loan_City__c = Con.MailingCity;
ObjEquipment.ELTON__Loan_Country__c = Con.MailingCountry;
ObjEquipment.ELTON__Loan_Name__c = Con.FirstName + ' ' + Con.LastName;
ObjEquipment.ELTON__Loan_State_Province__c = Con.MailingState;
ObjEquipment.ELTON__Loan_Zip_Postal_Code__c = Con.MailingPostalCode;
ObjEquipment.ELTON__Loan_Phone__c = Con.Phone;
ObjEquipment.ELTON__Loan_Other_Phone__c = Con.OtherPhone;
ObjEquipment.ELTON__Loan_Email__c = Con.Email;
ObjEquipment.ELTON__Loan_Mobile__c = Con.MobilePhone;
}
lstEQ2.add(ObjEquipment);
} // for equipment
} // if containskey
} // if correct fields changed
} // for trigger new
if(lstEQ2.size()>0)
{
update lstEQ2;
}
} // trigger
mapEQ.put(eq.ELTON__Assigned_Contact__c, new List<ELTON__Equipment__c>()); // create the list within the map
16:List<ELTON__Equipment__c> tempEQList = mapEQ.get(eq.ELTON__Assigned_Contact__c); // retrieve the list by key from the map
17:tempEQList.add(eq); // add your item to the list contained in the map