4

I am running a batch process that is marked without sharing.

I would like to to take one course of action if the batch process can update a particular field, and another if not.

For example:

if (canUpdate(fld)) {
  updateRecord();
} else {
  cloneRecordAndUpdateThat();
}

The naive way of writing canUpdate() is to use fld.getDescribe().isUpdateable(). However, that will always look at the current user's permissions. I specifically want to override user permissions, but sometimes fld is not updateable on a system level (e.g., the "master" field on a master-detail relationship that cannot be reparented).

How do I discover if "god-mode" without sharing permissions can update that field?

  • If you're doing it as a batch it should be running as an admin or API user with an admin profile. Using is updateable should work. If not even an admin can update it, clone it instead. Alternatively, you can look into using the tooling API. – gNerb Jul 30 '18 at 21:26
  • @gNerb No thank you. This is a batch process that many non-admin users can launch. I still want to keep track of which user launched the batch process. Additionally, there are fields that my admin users may not update but others can. – Charles Koppelman Jul 30 '18 at 21:28
  • I just played around and did some testing and I don't think the tooling API has what you need either. It seems to work like a normal describe call. – gNerb Jul 30 '18 at 21:34
  • Actually, it might be good enough for my current use case which just cares about reparentableMasterDetail – Charles Koppelman Jul 30 '18 at 21:42
  • 1
    Another approach although reactive but could be worthwhile considering is to execute an update within a try-catch and catching a DmlException in case it is not updateable and accordingly execute the further logic in the finally block. – Jigar Shah Jul 31 '18 at 2:25
1

I had this partway there, and you're welcome to check out and adapt my code that hits the Tooling API to discover if a Detail side of MasterDetail can be reparented, and makes a number of other assumptions about fields.

I then realized how complex it would be to maintain RemoteSiteSettings for developer and training sandboxes. But the straw that broke my code's back was discovering that batch processes and @future methods don't have UserInfo.getSessionId(), so I'd need an OAuth refresh_token.... All told, that was too much for me to deal with, so I went the route suggested in the comment above by Jigar.

It turns out, the exception thrown is not a DmlException, but an SObjectException with the message "Case__c is not editable", and it happens when you set the field, well before the update.

Below is my solution:

Boolean shouldCreateClones = false;
try {
  updateRecords(scope);  
} catch (System.SObjectException ex) {
  if (ex.getMessage().contains('is not editable')) {
    shouldCreateClones = true;
  } else {
    throw ex;
  }
}

if (shouldCreateClones) {
  cloneRecordsAndUpdateThose(scope);
}
| improve this answer | |

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.