You need to sign in to do that
Don't have an account?

Sets do not enforce uniqueness of sobjects according to documenation
Hello,
I'm trying to avoid duplicate sobjects in my list of sobjects that I submit for update/delete/insert. I realized that Sets are great for this. The documentation states the following concerning uniqueness of sObjects in Sets:
http://www.salesforce.com/us/developer/docs/apexcode/index.htm
"Uniqueness of sObjects is determined by IDs, if provided. If not, uniqueness is determined by comparing fields. For example, if you try to add two accounts with the same name to a set, only one is added"
However, in my experience, this is not the case. In the following example, I have provided the ID of the opportunities, but after changing one field, both opportunities are still added to the Set. This is not the expected behavior because the ID of the opportunities are supplied and identical.
Opportunity opp1 = [Select Id from Opportunity Where Id = '006Q00000054J7u']; Set<Opportunity> opps = new Set<Opportunity>(); opps.add(opp1); opp1.Name = 'Something new'; opps.add(opp1); System.debug('SIZE: ' + opps.size()); //prints 2, expect 1
What am I doing wrong? Is this an API version issue? I believe I'm using api version 19.0.
I will need to rewrite a lot of code if the Set uniqueness does not work as advertised.
Thanks for any help you might provide,
Andrew
There is a bug in the documentation. Hash codes are computed based on the field values, and do not treat the ID in any special manner. Thanks for finding that, I'll make sure the docs get fixed.
With respect to what's happening in the code, you can see the same behavior in Java. What's happening is that you're mutating an object that already exists in the set, changing its hashcode. So any further lookups will happen in the new hash location, but the old object is sitting at the old hash location. Here's a java program that illustrates the same thing:
A better way to have a data structure that guarantees uniqueness with sobjects is to use a map. Apex makes it easy to generate such a map from a query:
Rich
All Answers
I'm not sure about your underlying question, but it seems you could just check to see if the set contains the item before adding - if so, update the existing one, if not, update it? using the contains() method to check?
I'm sure someone else will come along and answer this better but at least that's an attempt ;-) HTH
Thanks for the quick reply. using 'contains()' will not work because it uses the same logic as add() to determine if the element is already in the Set (I assume). In Java, this would call hashCode(), and in Apex, I thought it compared an sObject's ID to the ID of the element you're trying to add (or a comparison of all the other fields if the ID field was not present).
Andrew
There is a bug in the documentation. Hash codes are computed based on the field values, and do not treat the ID in any special manner. Thanks for finding that, I'll make sure the docs get fixed.
With respect to what's happening in the code, you can see the same behavior in Java. What's happening is that you're mutating an object that already exists in the set, changing its hashcode. So any further lookups will happen in the new hash location, but the old object is sitting at the old hash location. Here's a java program that illustrates the same thing:
A better way to have a data structure that guarantees uniqueness with sobjects is to use a map. Apex makes it easy to generate such a map from a query:
Rich
Thanks for confirming that there is a bug in the documentation. I thought I was going a little crazy.
And with regard to your Java example, you are also correct. It all comes down to the equals and hashcode() implementation. Since Apex doesn't have these concepts (at least not explicitly), I assumed the having the same ID on two objects made them 'equal.'
Just before you responded I started changing my code to use Maps instead of Sets. Your response validates my new approach for managing update/delete/insert lists. It will do exactly what I had hoped for initially.
Thanks for your thorough response,
Andrew
Hi,
I have been tinkering around with equals() and hashCode() methods.
I have seen couple of sites for Java where the importance and usage of equals() and hashCode() method is explained in detail. But when it comes to Apex; its bit confusing.
I have a doubt that wheather we should provide implementation of hashCode() in Apex?
I have used the class in the documentation (PairNumbers); but did not provided the hashCode() implementation. Then I have gone to developer console and ran following code
After executing the code; I got the output as:
As per my understanding the hashCode() for p5 should be different than p3 and it should return null. I am missing something? I am not getting why we need to implement hashCode() method if only equals() method is doing the job or there my understanding is incorrect.
Thanks,
Mandy
Why should p5 be different than p3? As per the apex documentation:
This has to be true weither you implement the hashCode function or not. For that matter, it is part of the java docs as well:
You shouldn't have to implement the hashCode method, although you're right that the docs don't make that clear. From my understanding, the only time you would need to override the hashcode function is you wanted to change the hashcode function/functionality. Let's say you wanted to have two distinct values have the same hashcode, which is valid.