3

Can you see why this returns true:

Map<IObject, XYZ> records1Map = getRecords(1); // returns Map<MyObject, XYZ>
Map<IObject, XYZ> records2Map = getRecords(2); // returns Map<MyObject, XYZ>
for (IObject rec : records1Map.keySet())
{
    System.debug(records2Map);
    if (!records2Map.containsKey(rec)) return false;
}
return true;

but this returns false (same as above but without the debug statement)?

for (IObject rec : records1Map.keySet())
{
    if (!records2Map.containsKey(rec)) return false;
}
return true;

These are the method overrides:

public class MyObject implements IObject
{
    public SObject record { get; set; }

    public Boolean equals(Object o)
    {
        if (o instanceof MyObject)
        {
            MyObject compareTo = (MyObject)o;
            return this.record == compareTo.record;
        }
        else return false;
    }

    public Integer hashCode()
    {
        return JSON.serialize(record).hashCode();
    }
}

Btw I am aware of this question, however my overridden method signatures are correct.

6
  • 1
    Be aware that debugging settings affect whether hashCode is called - see hashCode() is never called when adding to Maps and Sets. And there have been bugs in the past such as System.hashCode broken on Id properties of SObjects?.
    – Keith C
    Commented May 19, 2016 at 19:32
  • Is this only an issue in unit tests? Because in my case I was actually running one! So would I be "fixing" the issue if I added the debug statement?
    – Mossi
    Commented May 19, 2016 at 19:50
  • Minor quibble, but you don't override anything when you implement these methods.
    – Adrian Larson
    Commented May 19, 2016 at 19:57
  • Think the core issue was the debug level not the System.debug statement but who knows how the two might or might not interact.
    – Keith C
    Commented May 19, 2016 at 19:57
  • 1
    By the way the System.hashCode method is advertised as working on SObjects.
    – Keith C
    Commented May 19, 2016 at 20:43

1 Answer 1

2

I cannot explain your results, though see the comment I've added to the question.

My attempts at trying to use value equality between SObject instances (where all the fields are compared) have never gone well. Such comparisons also use up a lot of the governor limited CPU time if many fields are involved. In the short term you may be fine, but if you use this approach everywhere in your code, eventually you will hit a case where hundreds of SObjects are being compared and the CPU time governor limit will be exceeded.

I recommend that you primarily stick to the simple strategy of comparing the ID values only: you could do that in a wrapper class like your MyObject if you wanted to. Then only use value equality for situations where that logic is specifically required.

3
  • Serialization is also a huge time hog.
    – Adrian Larson
    Commented May 19, 2016 at 20:10
  • That was a narrowed down sample code. I actually compare the Ids if they are present. But how do you recommend I compare the wrappers in absence of an id?
    – Mossi
    Commented May 19, 2016 at 20:18
  • @Mossi OK that's good. You could add an Integer "in memory only" ID to the wrapper populated from an incrementing static and use that if no ID is present (assuming you treat the wrapper as immutable). Or just don't wrap SObjects that don't have ID values as usually they are created/handled by explicit code that can keep track of them. But yeah maybe the value equality is the way to go for that case.
    – Keith C
    Commented May 19, 2016 at 20:25

You must log in to answer this question.

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