The underlying issue here is that, no matter what your approach is, you have to somehow deal with the fact that Description__c
is being set on the SObject instance you're using to upsert.
Even if it's being set to null, it still counts as the field being set/populated. All populated fields in an update/upsert will overwrite the current values stored in Salesforce.
If it's possible for you to simply not set Description__c
when you convert your external data to an SObject
instance, that'd probably be the easiest and least resource-intensive approach.
Beyond that, I think the only approach I can come up with involves creating a new in-memory instance of your SObject and using getPopulatedFieldsAsMap()
.
If you simply want to disregard a specific set of fields, something like the following should do the job
// I'm assuming that externalAcctData is properly set elsewhere in the code
Account externalAcctData;
Account acctCopy = new Account();
// Define which fields we want to _never_ update
Set<String> skipCopyOfField = new Set<String>{'Description', 'MyCustomField__c'};
// getPopulatedFieldsAsMap() does what it says on the tin
// The keyset of that map contains the api name of the field, which we can then use
// in the SObject put() and get() methods
for(String field :externalAcctData.getPopulatedFieldsAsMap().keySet()){
if(!skipCopyOfField.contains(field)){
acctCopy.put(field, externalAcctData.get(field));
}
}
// Now that we've created an instance of our SObject that does not have our target
// field(s) (the one(s) whose value(s) we want to preserve in the stored data in SFDC)
// set, we can use it to do our update/upsert instead of using externalAcctData
upsert acctCopy;
This is necessary because Salesforce does not provide us with a way to unset/un-populate a single SObject field at time of writing (Spring '20, API v48.0).