8

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.

2 Answers 2

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.

2
  • Great explanation, I didn't know! :) Jun 21, 2017 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. Jun 21, 2017 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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .