8

I couldn't find if SOQL and DML become interlinked when using WITH USER_MODE with SOQL and DML both in single transaction.

I've below sample code to be triggered on a button from an LWC:

@AuraEnabled
public static void ruleMoveOrder(String ruleId) {
    My_Rule_Obj__c rule     = [SELECT Id, Order__c, My_Rule__c FROM My_Rule_Obj__c WHERE Id = :ruleId WITH USER_MODE];
    rule.Order__c           = rule.Order__c + 1;
    Database.update(rule, AccessLevel.USER_MODE);
}

This code is causing an exception like this on DML statement line Database.update(rule, AccessLevel.USER_MODE):

"System.DmlException: Operation failed due to fields being inaccessible on Sobject My_Rule_Obj__c, check errors on Exception or Result!"

The Debug Logs generated shows this information:

03:53:30.5 (21945797)|SOQL_EXECUTE_BEGIN|[76]|Aggregations:0|SELECT Id, Order__c, My_Rule__c FROM My_Rule_Obj__c WHERE Id = :tmpVar1 WITH USER_MODE
03:53:30.5 (43468810)|SOQL_EXECUTE_END|[76]|Rows:1
03:53:30.5 (43721320)|VARIABLE_SCOPE_BEGIN|[76]|rule|My_Rule_Obj__c|true|false
03:53:30.5 (43776306)|VARIABLE_ASSIGNMENT|[76]|rule|{"Id":"a1C5g000005kyuUEAQ","Order__c":1,"My_Rule__c":"a115g0000009qd2AAA"}|0xee3a1fd
03:53:30.5 (43785988)|STATEMENT_EXECUTE|[78]
03:53:30.5 (44245154)|VARIABLE_ASSIGNMENT|[78]|this.Order__c|2|0xee3a1fd
03:53:30.5 (44256849)|STATEMENT_EXECUTE|[79]
03:53:30.5 (44346702)|VARIABLE_SCOPE_BEGIN|[6]|System.AccessLevel.SYSTEM_MODE|System.AccessLevel|true|true
03:53:30.5 (44367947)|VARIABLE_SCOPE_BEGIN|[4]|System.AccessLevel.USER_MODE|System.AccessLevel|true|true
03:53:30.5 (44432606)|SYSTEM_METHOD_ENTRY|[1]|AccessLevel.AccessLevel()
03:53:30.5 (44443041)|STATEMENT_EXECUTE|[1]
03:53:30.5 (47023769)|SYSTEM_METHOD_EXIT|[1]|AccessLevel
03:53:30.5 (47219802)|DML_BEGIN|[79]|Op:Update|Type:My_Rule_Obj__c|Rows:1
03:53:30.5 (47308428)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:8
03:53:30.5 (48128599)|DML_END|[79]
03:53:30.5 (49360391)|FATAL_ERROR|System.DmlException: Operation failed due to fields being inaccessible on Sobject My_Rule_Obj__c, check errors on Exception or Result!

The error would go away and able to update correctly, as it should with below code:

@AuraEnabled
public static void ruleMoveOrder(String ruleId) {
    My_Rule_Obj__c rule     = [SELECT Id, Order__c, My_Rule__c FROM My_Rule_Obj__c WHERE Id = :ruleId WITH USER_MODE];
    My_Rule_Obj__c rule2    = new My_Rule_Obj__c(Id = rule.Id);
    rule2.Order__c          = rule.Order__c + 1;
    Database.update(rule2, AccessLevel.USER_MODE);
}

Why would this be? Does SOQL query using USER_MODE makes the rule variable instance sort of readonly? Can we not directly update the variable with this security system in place?

NOTE:

  • Org wide sharing rule do not matter - object sharing settings are public read/write.
  • Field level and Object permissions properly enabled with full CRUD and FLS permissions to edit and Read.
5
  • Could you please share the entire method, instead of just those lines? Context may be important here.
    – sfdcfox
    Nov 19, 2023 at 21:31
  • @sfdcfox I've updated code. But the code I earlier posted also was full method code, just method definition with input parameters was missing.
    – VarunC
    Nov 19, 2023 at 21:54
  • The error message didn't sound like a standard error, which is why I asked.
    – sfdcfox
    Nov 19, 2023 at 22:10
  • The Exception type is System.DmlException: and I've updated that in my error message in the question. I was actually hoping this is new message syntax whenever USER_MODE specific error occurs, which means, platform identified some field not assessible to user for carrying out the DML or SOQL operation. My Apex class Api Version is 58.0.
    – VarunC
    Nov 19, 2023 at 22:18
  • All DML operations always throw DmlException. It used to be that various types would be thrown across DML boundaries, but this is no longer true.
    – sfdcfox
    Nov 19, 2023 at 22:22

2 Answers 2

3

My_Rule__c appears to be a master-detail relationship field with reparenting disabled. For some reason, supplying the same value as what is already in the field still causes this error, because the field cannot be specified in this configuration. When you used new My_Rule_Obj__c(Id = rule.Id), you didn't include the My_Rule__c field, which is why you didn't get the error message.

You can validate this hypotheses with a simple execute anonymous script:

Assert.isTrue(My_Rule_Obj__c.My_Rule__c.getDescribe().isUpdateable());

Which should fail if the field is indeed a master-detail relationship with reparenting disabled.

The moral of the story is: don't include fields you don't intend to update in your query.

1
  • That was is. Yes, it is a M-D field. Thank you so much!
    – VarunC
    Nov 20, 2023 at 7:20
0

I believe this is a bug with AccessLevels. Until it's fixed, you can use the following workaround:

List<My_Rule_Obj__c> rules = new List<My_Rule_Obj__c>{ rule };
List<My_Rule_Obj__c> strippedRules = Security.stripInaccessible(AccessType. UPDATABLE, rules).getRecords();
Database.insert(strippedRules, AccessLevel.USER_MODE);

More info: https://salesforce.stackexchange.com/a/412743/61394

1
  • 1
    Yes, that is what I'm doing, and I agree, it should be a bug, as if we have not modified a field then it should not be treated for modification in DML. At least that wasn't the case earlier.
    – VarunC
    Dec 8, 2023 at 8:21

You must log in to answer this question.

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