6

Can anyone explain the comments in this snippet?

Map<Account, Contact> m = new Map<Account, Contact>();
m.put(new Account(Name='Test'), new Contact(Lastname='Test'));

SObject[] records = new SObject[]{};
for (Account acc : m.keySet()) records.add(acc);
insert records;

System.debug(m); // returns {Account:{Name=Test, Id=0013600001BkcJYABC}=null}

System.debug(m.values()); // returns (Contact:{LastName=Test})

Specifically the map seems to lose its values once its keys are DML'd upon, and yet, the values appear to be there!

I think it is obvious that the map cannot identify its keys once they receive Ids. This looks like a pass-by-reference bug to me.

15

Using complex objects as Map keys can have unexpected consequences.

In your example, the insert causes the Id of the key Account to be updated so the hashCode and equals methods of the Account produce different results after that. But the Map was setup with the original hashCode and equals results. Effectively you have modified the key and that has broken the contract of the Map.

Using an immutable value as the key - such as an Id or a String or an Integer - is much safer.

|improve this answer|||||
  • Great explanation, I didn't know! :) – Javier García Manzano Jun 21 '17 at 8:41
  • 2
    Agreed. Ever since apex started allowing objects as members of Set and keys of Map, I've seen lots of developers try to use them and end up with surprising behavior. I haven't seen any use cases for sObject sets that aren't solved just as easily some other way. – Jeremy Nottingham Jun 21 '17 at 11:41
1

Once you updated Account, key in map is changed (as now Id field and its value differs, from original value). That means, that new hashCode is differs. This is a new key, and this map has no value for this key

|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.