When a set collection contains objects such as Opportunities, what is used to determine uniqueness when the same Opportunity record is added to the collection a second time? I'm guessing that the system is considering the entire object (a hash?) so that any changes in the field values of a record results in the collection considering it as a new Opportunity record rather than replacing the previous one.
If I run this code the final count on the setOpportunities collection reveals that my assumption is correct:
Map<Id, Opportunity> mapOpportunities = new Map<Id, Opportunity>();
mapOpportunities.putAll([SELECT Id, Name, Type FROM Opportunity LIMIT 2]);
system.debug('Count of records in mapOpportunities = ' + mapOpportunities.size()); //size equals 2
Set<Opportunity> setOpportunities = new Set<Opportunity>();
for(Opportunity objOpportunity : mapOpportunities.values())
{
setOpportunities.add(objOpportunity);
}
system.debug('Count of records in setOpportunities = ' + setOpportunities.size()); //size equals 2
for(Opportunity objOpportunity : mapOpportunities.values())
{
setOpportunities.add(objOpportunity);
}
system.debug('Display setOpportunities records after being added again: ' + setOpportunities); //displays 2 records
system.debug('Count of records in setOpportunities after being added again = ' + setOpportunities.size()); //size equals 2
for(Opportunity objOpportunity : mapOpportunities.values())
{
//edit each opportunity and add it to the set again.
objOpportunity.Name = objOpportunity.Name + ' - Updated';
setOpportunities.add(objOpportunity);
}
system.debug('Count of records in setOpportunities after being updated and added = ' + setOpportunities.size()); //size equals 4
What is odd is what happens if I display the setOpportunities collection in the log. If I add:
system.debug('Display setOpportunities records after being updated and added: ' + setOpportunities); //displays 2 records (shouldn't this display 4 records??)
Only the two updated Opportunity records are displayed. This sent me in circles for a while because I was debugging an upsert issue by displaying the content of the set and it appeared as if there was only 2 records rather than the actual 4.
Am I crazy? Any thoughts on why it only displays the 2?
Attribution to: Scott McClung
Possible Suggestion/Solution #1
I think what you are seeing is something related to the internal implementation of String.valueOf(Object) when the object is a Set and the subsequent conversion to JSON for inclusion in the log.
If I add the following towards the end of the anonymous Apex there are indeed 4 Opportunity records in the set.
//...
system.debug('Count of records in setOpportunities after being updated and added = ' + setOpportunities.size());
//size equals 4
system.debug('Display setOpportunities records after being updated and added: ' + setOpportunities);
//displays 2 records (shouldn't this display 4 records??)
for(Opportunity objOpportunity : setOpportunities)
{
System.debug(objOpportunity);
}
Debug log showing the 4 Opportunities in the Set.
Unfortunately you can't get the internal hashCode() for an sObject. See Expose the Object's hashCode() method in apex. You could potentially implement your own wrapper object with a custom hashCode()
implementation that uses the Id when available.
A simpler example
Add one Opportunity to a Set twice. Note the asserts do pass, but are commented out to make the logging easier to read.
Set<Opportunity> setOpportunities = new Set<Opportunity>();
Opportunity opp = new Opportunity();
opp.Name = '1';
setOpportunities.add(opp);
//System.assertEquals(1, setOpportunities.size());
opp.Name = '2';
setOpportunities.add(opp);
//System.assertEquals(2, setOpportunities.size());
If you look at the log you can see the Opportunity is at 0x5239e2f9 in the heap memory and the Set has allocated two references to it.
Mock up of the end state.
Attribution to: Daniel Ballinger
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/30492