Loading

SOQL queries and criteria-based sharing considerations

Udgivelsesdato: Jun 8, 2026
Beskrivelse

In Salesforce, if a with sharing Apex class runs a SOQL query within the same transaction where a criteria-based sharing rule should share rows with the running user, the query will not return those rows.


This is because criteria-based sharing rules are evaluated at the end of Apex execution. The sharing entries are written to the database during the commit phase — which occurs after all Apex code for the request has finished. 

 

Therefore, a SOQL query executed during the Apex transaction cannot access rows whose sharing has not yet been committed.

Løsning

Why Criteria-Based Sharing Rows Are Not Accessible in the Same Transaction

 

Per the Salesforce Order of Execution, criteria-based sharing rules are evaluated at the end of the execution flow. The shares created in memory during this evaluation are saved to the database during the commit phase — after all Apex execution for the request has finished.


Because the Apex transaction completes before the commit phase, any SOQL query run within the transaction cannot see rows shared via a criteria-based sharing rule that was also evaluated within the same transaction.

 

Workarounds

 

  • Change the Apex controller's sharing modifier from with sharing to without sharing, allowing the query to bypass sharing rule restrictions (use with caution — evaluate security implications first).
  • Invoke the required SOQL query in a separate transaction from the transaction where the criteria-based sharing rule is evaluated. This ensures the sharing has been committed before the query runs.

 

Sample Scenario for Reproduction

To reproduce this behavior in a test environment: Create an Apex controller with with sharing that inserts an Account record and then immediately queries it. Add a before-insert trigger that changes the OwnerId to a specific user (e.g., a user with the CEO role). Create a criteria-based sharing rule that shares accounts of a specific record type with users in roles below CEO.


When a user with a role below CEO runs the page and clicks the button to create the account, the SOQL query returns no results — "Could not query account" is displayed. This is because the sharing rule has not yet been committed at the time of the query. However, the same user can navigate directly to the Account record URL and view it successfully after the transaction completes.


Create the following Apex controller, Visualforce page, and Apex trigger.

public with sharing class AccountQueryIssue {
    public String debugString { get; set; }
    private Account a, b;    
    
    public AccountQueryIssue() {
        debugString = '';
    }
    
    public void createAccount() {
        // Replace record type ID with ID of an account record type
        a = new Account(Name = 'Acme '+ System.now(), recordTypeId='012410000002S6O');
        insert a;
        debugString += '<br/>Inserted account:<br/>' + JSON.serialize(a) + '<br/>';

        try {
            b = [SELECT Id, Name, Owner.Alias FROM Account where id = :a.Id];
        } catch(Exception e) { }
        
        if(b != null)
            debugString += '<br/>Queried account:<br/>' + JSON.serialize(b) + '<br/>';
        else
            debugString += '<br/>Could not query account<br/>';
    }
}

VF Page

<apex:page controller="AccountQueryIssue" showHeader="false" sidebar="false">
    <apex:form >
        <apex:commandButton action="{!createAccount}" value="Create Account"/>
    </apex:form>
    <apex:outputText escape="false" value="{!debugString}"/>
</apex:page>

Apex Trigger

trigger ChangeOwner on Account (before insert) {
    for(Account a : Trigger.new) {
        // Replace OwnerId with ID of user with role CEO
        a.OwnerId = '00541000000HJYT';
    }
}

 

Yderligere ressourcer

Order of Execution in Apex

Vidensartikelnummer

000382331

 
Indlæser
Salesforce Help | Article