13

I am upserting list of records based on externalId as follows:

List<Database.upsertResult> results = Database.upsert(lstRecords, CustomObject__c.External_Id__c,true);

The results returns as follows:

(Database.UpsertResult[getErrors=();
                        getId=a1k0j000000P6CmAAK;
                        isCreated=true;
                        isSuccess=true;], 
 Database.UpsertResult[getErrors=();
                        getId=a1k0j000000P6CNAA0;
                        isCreated=false;
                        isSuccess=true;])

The first record is inserted and 2nd record is updated.

Since I am upserting based on externalId, I need to know for which ExternalId the records have been successfully inserted or updated.

UpsertResult Class doesn't expose any methods. It returns SalesforceId and NOT externalId

I need a results structure like this:

(Database.UpsertResult[getErrors=();
                        getExternalId = '1234';
                        getId=a1k0j000000P6CmAAK;
                        isCreated=true;
                        isSuccess=true;], 
 Database.UpsertResult[getErrors=();
                        getExternalId = '1235';
                        getId=a1k0j000000P6CNAA0;
                        isCreated=false;
                        isSuccess=true;])

What would be the best way to achieve this.

2 Answers 2

26

The order of the results are the same as the order of the original list. As long as you know the order of the original list (e.g. you didn't do something like Database.upsert(mapRecords.values(), field);), you'll know the order of the results. If you do not know the order, because it's in a map, you can still get the Id from the result (mapRecords.get(result.getId()).ExternalId__c) to get the appropriate record.

Here's how I typically get the results from a DML operation:

Database.UpsertResult[] results = Database.upsert(lstRecords, Object__c.Field__c);
for(Integer index = 0, size = results.size(); index < size; index++) {
    if(results[index].isSuccess()) {
        if(results[index].isCreated()) {
            System.debug(lstRecords[index].External_Id__c +' was created');
        } else {
            System.debug(lstRecords[index].External_Id__c +' was updated');
        }
    }
}
5
  • please find my answer, I have taken this approach Commented Aug 20, 2017 at 20:20
  • We do know order, even if we use a values() call on a Map. Per the documentation (developer.salesforce.com/docs/atlas.en-us.apexcode.meta/…), calling the values() method yields a deterministic list... each call will yield the same list in the same order. It has been this way since Summer ’15 release.
    – krigi
    Commented Dec 6, 2018 at 0:38
  • @krigi Yes, I'm aware of that, but we've also been told not to depend on this patch always working (note that the docs say "You can rely on the order being the same in each subsequent execution of the same code."). It does help in common use cases, but I still wouldn't recommend depending on it without testing edge cases, like when passing records between classes in different API versions, etc.
    – sfdcfox
    Commented Dec 6, 2018 at 5:29
  • @sfdcfox thanks for the response. But who told us not to depend on this patch always working? ... "You can rely on the order being the same in each subsequent execution of the same code." to me this reads pretty plain... if we call MapAlpha.values() N times... we will receive the same, ordered list each time. Have you observed different behavior? If this method does not work as advertised, SFDC needs to rework their docs :)
    – krigi
    Commented Dec 6, 2018 at 19:00
  • @krigi Who I don't recall, it was when it was first announced and there was a speaker Q&A. You're right that you can depend on in within the same class in the same transaction, but I think the problem is that there's no guarantee if you use multiple transactions (e.g. in a visualforce controller in multiple action methods). I don't have a concrete example, but I'll see if I can find out more.
    – sfdcfox
    Commented Dec 6, 2018 at 21:45
2

I have implemented my requirement with this approach. Thanks to @sfdcfox

//create a return structure
private class JsonUpsertResult
    {
        List<Database.Error> Errors {get;set;}
        String SFDCId {get;set;}
        String ExternalId {get;set;}
        Boolean isCreated {get;set;}
        Boolean isSuccess {get;set;}
    }

List<Database.upsertResult> results = Database.upsert(lstRecords, CustomObject__c.External_Id__c,true);

//loop through the results and add values from Database.upsertResult
List<JsonUpsertResult> lstJsonUpsertResult = new List<JsonUpsertResult>();
for(Integer index = 0, size = results.size(); index < size; index++) 
{
    JsonUpsertResult resultRow = new JsonUpsertResult();
    resultRow.Errors =  results[index].getErrors();
    resultRow.SFDCId = results[index].getId();
    resultRow.ExternalId = lstRecords[index].External_Id__c;
    resultRow.isCreated = results[index].isCreated();
    resultRow.isSuccess = results[index].isSuccess();
    lstJsonUpsertResult.add(resultRow);
}

System.debug(JSON.serialize(lstJsonUpsertResult));

Output

[{"SFDCId":"a1k0j0000001OriAAE",
        "isSuccess":true,
        "isCreated":true,
        "Errors":[],
        "ExternalId":"943458"}
,{"SFDCId":"a1k0j0000001OreAAE",
    "isSuccess":true,
    "isCreated":false,
    "Errors":[],
    "ExternalId":"943454"}]
1
  • 1
    not sure how it is downvoted. Commented May 16, 2018 at 17:40

You must log in to answer this question.

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