15

As we know that set<Sobject> and list<Sobject> are collection type.

So basic question I do have why Set doesn't support DML operation ?

We can perform DML on List<Sobject> but why not on set<Sobject>

Any idea?

1

3 Answers 3

17

One reason may be that Set<SObject> is a risky mechanism to use: equality is based on all the fields (so is expensive) and if fields are changed logic can easily break. Same problem using SObject as a Map key. So not a pattern to be encouraged.

But perhaps just because also supporting Set<SObject> adds a bunch of extra methods that need documenting and supporting. (Given that there isn't any common superclass.) And the conversion to list is trivial:

Set<SObject> s = ...;
someDmlOperation(new List<SObject>(s));
6
  • Set equality for objects (including SObjects) being added to a set (to determine if it already exists in the set or not) is actually based on a hash, rather than a literal comparison of every field, which means it's ludicrously fast (~0.010189 CPU limit per .add() vs ~0.011671 CPU limit per result = sObject1 == sObject2;). Still, your point about the risks of Set<SObject> is good.
    – Derek F
    Commented Aug 17, 2017 at 14:30
  • @DerekF Expensive in the sense that for say a 200 field SObject the hashes of all 200 fields need combining into the single hash for the object. And should a hash bucket have multiple values the equals will require a comparison of the 200 fields too. So fast compared to say a database call, but potentially quite a consumer of the CPU limit if many SObjects are involved. (Think the time will be roughly proportional to number of populated fields, but good to know of order of 10ms.)
    – Keith C
    Commented Aug 17, 2017 at 15:03
  • I see, but I'm not quite convinced. I think that SF computes the hash of objects as BLOBs rather than hashing individual fields. Time for another round of benchmarking!
    – Derek F
    Commented Aug 17, 2017 at 15:40
  • 1
    @DerekF Interesting if they do, but as the hash needs to change when a field is changed not sure that much can be done to optimise. But you are right: best to have some real measurements rather than speculation. It remains that the key point is the unpredictable results: I've tried to use SObjects as keys in the past and always ended up giving up because business logic usually changes fields and so breaks any hashed collection the SObjects are already in.
    – Keith C
    Commented Aug 17, 2017 at 15:51
  • 1
    Ran another quick-and-dirty benchmark on adding an SObject to a set with all of its fields and with only a single field. The object I tested with has 102 fields, and the overall time for .add()-ing all 644 records, 1000 times (total of 644,000 calls to .add()) came to 11552 CPU time / 11999 ms for all 102 fields, and 3374 CPU time / 3437 ms for the single field. That comes to 0.017938 CPU time / 0.018632 ms (i.e. 18 us) per record with all 102 fields vs 0.05239 CPU time / 0.005337 ms (5 us) per record with a single field. Growth appears to be linear at ~0.3 us per additional field.
    – Derek F
    Commented Aug 17, 2017 at 15:53
5

Sets (and Maps) cannot be cast to Sets of a different type. For example, Set<sObject> t = (Set<sObject>)new Set<Contact>() will fail with the message Incompatible types since an instance of Set<Contact> is never an instance of Set<SObject>. The database methods, and presumably DML keywords, are not implemented as generic methods, so they could only take a Set<sObject>, not any concrete sObject type. That would be a radical departure from the behavior of the List overloads, which can take either a List<sObject> or e.g. a List<Contact>, because lists are implicitly convertible from a contained type to a superclass of that contained type.

Most likely, the methods were not implemented as generics just because it would make the syntax awkward, since you would need something like insert<Contact> new Set<Contact>(), or they would need to add special compiler logic to deduce the type of the passed object. The actual upside is pretty minor as well, as Keith C's answer explains, since Set<sObject> can have behavior that is surprising to developers, and converting it to a list is relatively minor.

3

The values inside a set are supposed to be immutable; changing them means that values can be "lost" inside the object until the next time you debug the object, which seems to reset its internal state. In other words, it could introduce all kinds of subtle bugs, particularly on insert/upsert operations.

You must log in to answer this question.

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