There isn't any issue with storing multiple copies of an SObject
in a List
, at least not until you try to perform some DML on that List
(as you've discovered).
That said, your code doesn't behave the way you think it does. The good news is that the way your code does behave will end up making things easier.
Let's take a look at a specific part of your code:
for(Contact ct: retreivedContacts) {
if(ct.isBilling) {
Contact cnt = ct;
cnt.Trade_Show_Main_Directory_Contact__c = false;
contactsToSend.add(ct);
}
...
}
In this code, the Contact cnt = ct;
line does not make a copy of the Contact
represented by ct
. Instead, it makes a new reference to the Contact
represented by ct
. (If you wanted a completely separate copy, you would need to use ct.clone()
).
When you are working with a reference (as you are in this case), a change to a field of one of the references will cause that field to be changed on all references to that particular SObject
.
So Contact cnt = ct;
ends up doing very little. It can be removed completely without consequence. Furthermore, for(Contact ct :retrievedContacts)
also stores a reference (not a separate copy) of each Contact
from your retrievedContacts
list in ct
. Changing ct
inside of the loop will change the value stored in the Contacts
in retrievedContacts
.
Given all of that, we can shorten your code (and also resolve the issue you were running into).
This code is functionally equivalent to the snippet you've provided.
List<Contact> retreivedContacts = getContacts();
// The line below is only necessary if you need to gather billing/internal contacts
// specifically for other processing later in your code.
//List<Contact> contactsToSend = new List<Contact>();
for(Contact ct: retreivedContacts) {
// Since you're updating the same field in both if blocks, we can consolidate them
if(ct.isBilling || ct.isInternal) {
// Since ct is a reference to an SObject in retrievedContacts, there's
// no need to create a separate Contact variable, nor is there a need
// to add ct to another list (unless you are doing specific processing
// for billing/internal contacts later on in your code).
ct.Trade_Show_Main_Directory_Contact__c = false;
// If you are going to add things to contactsToSend, it's best to try to
// only add it once.
// If your logic isn't quite this simple, so that it can't easily be
// handled by a single 'if' block and you could possibly add the same
// record to the list more than once, then a Map<Id, Contact> would
// be more appropriate to use (rather than a list).
//contactsToSend.add(ct);
}
}
// With the code you've provided us, this is all you would need to do to update
// record values.
// update retrievedContacts;