3

I have a utility method that that works on lists of SObjects that are normally of one type:

private void oneType() {
    Contact[] contacts = new Contact[] {};
    contacts.add(new Contact(...));
    contacts.add(new Contact(...));
    upsertUtility(contacts);
}

but occasionally I want to use the method with lists of mixed SObject type:

private void mixedType() {
    SObject[] mixed = new SObject[] {};
    mixed.add(new Contact(...));
    mixed.add(new Account(...));
    upsertUtility(mixed);
}

For the second mixed case this error occurs:

DML on generic List only allowed for insert, update or delete

because of a known issue in the platform.

So I'm wondering if it is possible to detect the unsupported case for the rare occasions it comes up and use upsert for the common case. So the question is can the type of the list be detected i.e. what code could replace the ??? in this code:

private void upsertUtility(SObject[] sobs) {
    if (???) insertUpdate(sobs);
    else upsert sobs;
}

private void insertUpdate(SObject[] sobs) {
    SObject[] updates = new SObject[] {};
    SObject[] inserts = new SObject[] {};
    for (SObject sob : sobs) {
        if (sob.Id != null) updates.add(sob);
        else inserts.add(sob);
    }
    update updates;
    insert inserts;
}

Concrete lists of SObject types are subclasses of lists of SObject so instanceof doesn't help and there is no way I can see to get the type of a list. But I may be missing something.

  • you can pass a second parameter if you are sending a generic list. if its easy to introduce. – Tushar Sharma Sep 4 '17 at 16:05
  • 1
    @TusharSharma Yes an extra parameter is what I am using but that means the caller has to get the parameter right which is not ideal. – Keith C Sep 4 '17 at 16:29
  • then you can try my answer if thats suits you. – Tushar Sharma Sep 4 '17 at 16:38
3

You can't use upsert if the list is generic, even if it only contains one type of records. Basically, you can use getSObjectType(), and if it's null, you can't upsert:

if(sobs.getSObjectType() == null) {
   doInsertUpdate(sobs);
} else {
   Database.upsert(sobs);
}
| improve this answer | |
  • That's exactly what I'm looking for. I didn't know that lists of concrete SObject types support getSObjectType(); is that documented somewhere? Compiles and works well for me. – Keith C Sep 4 '17 at 16:52
  • @KeithC Sorry, had to step out for a bit. It's actually mentioned in the List Class documentation. – sfdcfox Sep 4 '17 at 21:35
  • Thanks! Thought I'd looked there but must have missed it. – Keith C Sep 4 '17 at 21:38
0

As I have mentioned in comment you can pass a second parameter and based on that call your method.

Or in your generic method you can take help from sObject describe to decide if you can use upsert or not.

List<Account> accList = new List<Account>();
accList.add(new Account());
accList.add(new Account());
Set<Schema.sObjectType> sObjectType = new Set<Schema.sObjectType>();
for(Account acc : accList){
    sObjectType.add(acc.getSObjectType());
}
system.debug(sObjectType.size() );

enter image description here

in first use case if you check size it will return 1. Now we check the case of generic list. You can also use break to reduce the total number of iteration if you have found multiple records.

List<sObject> sObList = new List<sObject>();
sObList.add(new Account());
sObList.add(new Contact());
Set<Schema.sObjectType> sObjectType = new Set<Schema.sObjectType>();
for(sObject acc : sObList){
    sObjectType.add(acc.getSObjectType());
}
system.debug(sObjectType.size() );

enter image description here

Now you can check size of this set and can call different methods.

if (sObjectType.size() > 1) insertUpdate(sobs);
    else upsert sobs;
| improve this answer | |
  • Thanks for answering. My scenario is a bit different in that the list gets created as either List<SObject> (that often only includes one type of SObject but can have more types) or List<Contact> (that has to only include one type of SObject). For the List<SObject> list, in addition to the type checking code you've posted that establishes one type only, to be able to do the upsert the correct type of list would have to be created via Type.forName and the items copied over. I'd like to avoid all that. – Keith C Sep 4 '17 at 16:48

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.