When SObjects are used as Map keys they are compared by field values, so for example:
Account a = new Account();
Account b = new Account();
System.debug(a == b); // Prints true
Map<SObject, Boolean> m = new Map<SObject, Boolean>();
m.put(a, true);
m.put(b, false);
System.debug(m.get(a)); // Prints false
What I want instead is for them to be stored as separate keys. I've managed to achieve this by creating a wrapper class and overriding equals()
using the exact equality operator (===
).
private class SObjectReferenceWrapper
{
public SObject Record;
public SObjectReferenceWrapper(SObject record)
{
this.Record = record;
}
public Boolean equals(Object obj)
{
if (obj instanceof SObjectReferenceWrapper)
{
SObjectReferenceWrapper o = (SObjectReferenceWrapper)obj;
return (Record === o.Record);
}
return false;
}
}
Usage:
SObjectReferenceWrapper o = new SObjectReferenceWrapper(new Account());
SObjectReferenceWrapper o2 = new SObjectReferenceWrapper(new Account());
System.debug(o == o2); // Prints false
Map<SObjectReferenceWrapper, Boolean> m = new Map<SObjectReferenceWrapper, Boolean>();
m.put(o, true);
m.put(o2, false);
System.debug(m.get(o)); // Prints true
Account a = new Account();
SObjectReferenceWrapper o = new SObjectReferenceWrapper(a);
SObjectReferenceWrapper o2 = new SObjectReferenceWrapper(a);
System.debug(o == o2); // Prints true
Map<SObjectReferenceWrapper, Boolean> m = new Map<SObjectReferenceWrapper, Boolean>();
m.put(o, true);
m.put(o2, false);
System.debug(m.get(o)); // Prints false
Unfortunately, relying on equals()
alone causes put()
calls to take an incredibly long time once the map has 10-15 keys in it, so I need to implement hashCode()
to resolve this. This is where I've come unstuck.
When all of the field values are the same the build in hashCode()
method returns the same value, so that's no use.
I did also consider using the memory addresses of the objects which are show in in debug logs under VARIABLE_ASSIGNMENT, however it doesn't look like these are exposed via. Apex.
Have I come to a dead end where the limitations of the platform make this impossible (I hate that word), or am I missing something really obvious?
tl;dr
I need to create a Map using in memory SObjects as keys. Each in memory SObject should be treated as a unique value if it occupies a different location in memory, even if they have the same field values. Is this possible?