22

Are sObjects supported as the keys for Maps?

I thought they were, but it appears that any subsequent changes to the key sObject break the mapping to the value.

This might be better shown with an anonymous apex example (API v27.0).

Map<OpportunityLineItem, string> testMap = new Map<OpportunityLineItem, string>();
OpportunityLineItem testOli = new OpportunityLineItem();
testOli.Description = 'foo';
testMap.put(testOli, 'bar');
System.assert(testMap.containsKey(testOli));
string mapValue = testMap.get(testOli);
System.assertEquals('bar', mapValue);

// After this the OLI will no longer be a key in the map.
testOli.OpportunityId = '0064000000RB2eJ';

System.assert(testMap.containsKey(testOli), 'Expected to still contain OLI');
string mapValue2 = testMap.get(testOli);
System.assertEquals('bar', mapValue2, 'OLI instance still expected to map to string bar');

This fails for me with:

System.AssertException: Assertion Failed: Expected to still contain OLI

Is this the expected behaviour?

21

Yes, that is the expected behavior. Behind the scenes, Salesforce is hashing the sObject. By changing field values, you change the hash. A better practice is to use the sObject ID as the key. This blog post explains some more: https://appirio.com/tech-blog/considerations-using-sobjects-in-sets-and-map-keys-in-apex

When planning to use an SObject as the key for a Map, be aware that it can sometimes behavein an unexpected fashion. If you are expecting to encounter a scenario where the SObject can be mutated (even indirectly, as done by an insert) once set as a key for this Map, you will lose the reference to the value for this Map for the SObject key that was mutated.

| improve this answer | |
  • The hashing makes sense, as the Map still has the correct size, but couldn't find the updated sObject. – Daniel Ballinger Jun 5 '13 at 4:19
  • 2
    Link is broken, unfortunately. – Caspar Harmer Aug 31 '16 at 7:12
10

Doh, it appears it is the expected behaviour.

Uniqueness of keys of all other non-primitive types, such as sObject keys, is determined by comparing the objects’ field values.

Be cautious when using sObjects as map keys. Key matching for sObjects is based on the comparison of all sObject field values. If one or more field values change after adding an sObject to the map, attempting to retrieve this sObject from the map returns null. This is because the modified sObject isn’t found in the map due to different field values. This can occur if you explicitly change a field on the sObject, or if the sObject fields are implicitly changed by the system; for example, after inserting an sObject, the sObject variable has the ID field autofilled. Attempting to fetch this Object from a map to which it was added before the insert operation won’t yield the map entry, as shown in this example.

Source - Map Considerations

| improve this answer | |

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.