9

I'm getting an error when attempting to compile my Apex:

Upsert requires a concrete SObject type

In my code, I'm unable to create a concrete declaration for the container which I want to upsert. Any help would be appreciated.

    String type = 'Account';  
    System.Type typeOfMappedSObject = System.Type.forName(type);
    String qry = 'Select id from ' + typeOfMappedSObject.getName() + ' Where name=null'; 
    List<SObject> s_targetRecordList = Database.query(qry); 

    //...

    Map<String,Schema.SObjectField> sObjFieldMap =  sobjDscrbResult.fields.getMap(); 

... at this point I call createSObject(type) and receive a new SObject with specified type passed in as a string and assign it to a generic SObject which I later add to s_targetRecordList as seen below.

    SObject s_targetSObject = createSObject(type); 

    //... 

    for(String fieldName : sObjFieldMap.keyset()){
        if(fieldName == sfsmRecord.TargetFieldName__c){
            s_externalIdField = sObjFieldMap.get(fieldName);
        }
     }

    //... 

    s_targetRecordList.add(s_targetSObject);

    //.... 

    List<Database.UpsertResult> upsrtResultList = Database.upsert(s_targetRecordList, s_externalIdField, false);

One final note, if I remove the externalIDField from the Upsert call then I don't get the above error...

5

That is correct, you cannot upsert on a List of SObject when you specify external ID. Error: "Upsert with a field specification requires a concrete SObject type"

Please vote for the idea here : https://success.salesforce.com/ideaView?id=08730000000aNhVAAU

Conceptually what you require is : DYNAMIC TYPECASTING. But I am not sure if dynamic typecasting can be done.

Currently this should work for you:

String type = 'Account'; 
System.Type typeOfMappedSObject = System.Type.forName(type);
String qry = 'Select id from ' + typeOfMappedSObject.getName() + ' Where name=null'; 
List<SObject> s_targetRecordList = Database.query(qry); 
if(!s_targetRecordList.IsEmpty() && type == 'Account'){
    List<Account> accList = new List<Account>();
    accList = (List<Account>)s_targetRecordList;
}

Keep using accList for further operation including upsert.

  • Thanks Amit. I was trying to avoid a long series of if/then statements and really focusing on making this dynamic enough so future Dev intervention won't be required (i.e. if a newly created custom object needs to be used instead of an Account...) I'll vote up the idea - but I find it unusual that I can Upsert the generic SObject without the External ID successfully... It's been a bit of a head scratcher honestly... – jangiz Jan 2 '15 at 16:41
  • I also came across a thread now : developer.salesforce.com/forums/… – Amit Bangad Jan 2 '15 at 17:19
  • The solution proposed by Adrian Larson in the idea works great for me. – Semmel Jul 26 '18 at 10:58
1

I wasn't able to find any way to use Upsert with an Ext ID and a generic List. As a workaround I split the source data into two lists by querying the target org for the Ext ID value and capturing all corresponding Record IDs. Those with an ID went into the Update list and those without went into the Insert list. This technique will allow the use of generic SObjects lists without needing future code changes.

1

I would suggest to create a method overload for each type you are expecting, determining the type dynamically, casting the list to that type, then call the method and let the argument (List) determine the field.

So something like this:

private List<Database.UpsertResult> internalUpsert(List<Account> objects)
{
return upsrtResultList = Database.upsert(objects, s_Account_External_Id, false);
}

private List<Database.UpsertResult> internalUpsert(List<Contact> objects)
{
return upsrtResultList = Database.upsert(objects, s_Contact_External_Id, false);
}

It's not quite as dynamic as it could be, but it should help you out some. On dynamically casting Lists, here is a source I found: Apex Cast sObject list dynamically to a specific sObject Type

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.