4

I have a Set which appears to have duplicate values. Here is the pseudocode:

list<SOBject__c> list1 = [select id from SObject__c where blah blah blah];
list<SObject__c> list2 = [select id from SObject__c where blah blah blah];
list<SObject__c> list3 = [select id from SObject__c where blah blah blah];

set<SObject__c> combinedSet = new set<SObject__c>();
combinedSet.addall(list1);
combinedSet.addall(list2);
combinedSet.addall(list3);

A few of the items in list1 and list3 are identical. My expectation is that when I add all three lists to the set, that addall() will ignore any element that's already present in the set. However, when I iterate through combinedSet and look at SObject__c.Name, the items that overlap in list1 and list3 are in the set twice. (I do not have records with the same SObject__c.Name.)

How is this possible?

EDIT: Since there have been questions, I decided to be a bit more verbose and share most of the actual code. I'm going to share the part of the code that I believe is relevant. I have an object called Show__c. I'm querying against Show__c three times with three different conditions. That gives me three lists. But there are some records in Show__c for which two of the conditions are true, so two of the three lists overlap. That's why I use a set to remove the duplicates.

list<Show__c> list1 = [select id from Show__c where condition A];
list<Show__c> list2 = [select id from Show__c where condition B];
list<Show__c> list3 = [select id from Show__c where condition C];
set<Show__c> allShows = new set<Show__c>();
allShows.addall(list1);
allShows.addall(list2);
allShows.addall(list3);

Next I have another object called Hop__c which has two fields, a Master-Detail with Show__c and a Date. I insert the Show__c records from the set into Hop__c.

list<Hop__c> toInsert = new list<Hop__c>();

for (Show__c s : allShows) {
    Hop__c b = new Hop__c();
    b.Show__c = s.id;
    b.Week_Starting__c = date.today().adddays(1); 
    toInsert.add(b);
}

if (!toInsert.isempty()) insert toInsert;

After this runs (this is a Scheduled Apex), I look in Hop__c (which was previously empty) by generating a "Shows with Hops" report from within the SFDC UI. In the report I see the several instances of the same Show__c, which should not happen. When I run each individual query that generates the lists, I see some of the same records in list1 and list3, and those same records show up as duplicates in Hop__c. It's as if the set is storing duplicates.

7
  • What do you mean by "I do not have records with the same SObject__c.Name"? If they don't have the same name, they are not the same sobject__c record, and therefore, not duplicates. – JimRae Feb 7 '15 at 2:18
  • Are they in fact the same record? If they have different Ids for example, then they are considered unique. See what constitutes a unique record here: salesforce.com/us/developer/docs/apexcode/Content/… – James Loghry Feb 7 '15 at 3:25
  • You pseudo code does not match what you are doing as Name would be null in your example. Just shooting for the moon here but sObjects are considered unique base on field comparisions. It could be possible that with formula fields on the object or something else between list 1 and list 3 being executed that something on them made them different. Is it always the same IDs? Did you check to see if the ID's were the same and not the name? – Eric Feb 7 '15 at 3:29
  • @JimRae - what I meant was that in the database I do not have records with the same Name. So when I see the same Name appearing in the Set, they must have the same id. – eyedar Feb 8 '15 at 0:20
  • @JamesLoghry - I'm certain they are the same record. That's what makes this so troubling. – eyedar Feb 8 '15 at 0:24
1

Unless you've selected every possible field in the <sObject> with each query, I think you need to do something like limit the returned fields to only the same 2 fields or simply put your results into sets of Ids as I'm showing in the code below. Once you do, I believe you'll get different results than what you got initially:

map<Id, sObject> mapSO1 = new map<Id,sObject>([select Id,Name Where condition A]);
map<Id, sObject> mapSO2 = new map<Id,sObject>([select Id,Name Where condition B]); 
map<Id, sObject> mapSO3 = new map<Id,sObject>([select Id,Name Where condition C]);

set<Id> combinedSet = new set<Id>();

combinedSet.addall(mapSo1.keyset());
combinedSet.addall(mapSo2.keyset());
combinedSet.addall(mapSo3.keyset());

Now, test the above records for duplicates using the method of your choice in a for loop.

Without knowing the conditions and the fields you've returned, it's difficult to say why you're getting the results you are since you're currently putting all the records into sets as sObjects.

I don't believe an instance of a list of sObject records containing records with say 2 fields in it is the same as an instance of the same list where each record contains 5 fields that have been returned from the same query. If evaluated, I believe they wouldn't show as being equal or equivalent to one another.

However, the lists would both contain the same record Ids and the resulting sets would only contain one record Id. To me, the latter would be the "litmus test"; thus the reason for changing the structure of your test.

Using sObjects, it would seem the sets could contain two records with the same Id since instances of the two sObject records would not be equivalent because of the difference in the number of fields that each contained. Merging instance records with the same Id would be the only way to make them equivalent to where they contained all the same data and thus were "equal".

10
  • I will try this and report back the results. It sounds promising. However, I am querying for the same field in each query (namely id). Instead of obfuscating my code I'm thinking I should just put my entire code block here, as I sense there is something that that inherent in my objects that's causing this issue. – eyedar Feb 8 '15 at 0:29
  • Yes, please report back with your results. If it doesn't solve your issue, will be happy to look at your full code block to see if can spot something else that might be causing the issue. Unless keeping the full sObject is essential for some reason, having the Ids in a set should allow you to reference what you want at a later time from one of the Maps. – crmprogdev Feb 8 '15 at 14:41
  • Just posted an edit that includes more of my source. – eyedar Feb 8 '15 at 22:49
  • To do what you want in the code you've posted, all you need are the Ids, not the sObjects particularly since all you're using from the set is the Id which you can assign as the Id of b.Show__c in your For loop as you do right now except instead of using s.Id, it becomes s where s is the Id. Did you try what I suggested to see if it resolved your problem? – crmprogdev Feb 9 '15 at 14:00
  • If I use s instead of s.Id, then Eclipse complains that Save error: Illegal assignment from SOBJECT:Show__c to Id...I'm about to try what you suggested. – eyedar Feb 9 '15 at 17:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.