ApexSensei

Drills SOQL queries

WITH USER_MODE versus system mode

SOQL queries · Intermediate · 13 min · Runs in your Salesforce Developer org · Apex Path

Run the same owned-Ids query twice, once in system mode and once with `WITH USER_MODE`, then compare the counts. The point is to see which rows a USER_MODE query still returns when the running user owns them.

Lesson

Why this matters

Apex normally runs SOQL in system mode, which ignores field-level security and sharing. That is convenient while writing a trigger, but it also means a lookup helper can leak rows the running user is not allowed to see. WITH USER_MODE tells the query to run as the calling user, so hidden fields and unshared rows disappear from the result.

The smallest working example

List<Account> rows = [
    SELECT Id, Name FROM Account
    WHERE Id IN :ids
    WITH USER_MODE
];

If the user cannot see one of those Accounts, that row is simply left out of rows. For a user who owns the rows, the result is the same as system mode.

Name the parts

  • **WITH USER_MODE** goes after the WHERE clause (before ORDER BY/LIMIT).
  • The query uses the running user's sharing rules and field-level security.
  • Pair USER_MODE with **Security.stripInaccessible** when you do DML, so writes also respect field permissions.
  • The query still binds variables the same way; USER_MODE does not change the syntax.

A common wrong version

List<Account> rows = [SELECT Id FROM Account]; // system mode, no filter

Two problems. There is no WHERE clause, so the query reads the whole table. And it runs in system mode, so it can see rows the user is not allowed to see.

The fix

Filter to the owned Ids and run the same query twice. The second one adds WITH USER_MODE:

Integer systemCount = [SELECT COUNT() FROM Account WHERE Id IN :createdIds];
Integer userCount = [
    SELECT COUNT() FROM Account WHERE Id IN :createdIds WITH USER_MODE
];

Both counts should be 2 for the running user, because they own the Accounts.

Now you try

The starter inserts two Accounts and collects their Ids in createdIds. Count both queries, print System count: and User count:, then print Match: with whether the counts are equal.

Learn more

The challenge

Run the same owned-Ids query twice and count the rows each mode returns.

Examples:

  • Query without USER_MODE → System count: 2
  • Query with WITH USER_MODE → User count: 2
  • Comparing the counts → Match: true

Requirements:

  1. Uses WITH USER_MODE should be present: the second query uses WITH USER_MODE exactly.
  2. Scopes queries by owned Ids should be present: both queries bind createdIds in the WHERE clause.
  3. System count: 2 should be printed for the system-mode query.
  4. User count: 2 should be printed for the USER_MODE query.
  5. Match: true should be printed when the two counts are equal.

Starter code

String tag = 'AS-Q317-' + UserInfo.getUserId() + '-' +
    String.valueOf(Datetime.now().getTime());
List<Account> seeded = new List<Account>{
    new Account(Name = tag + '-A'),
    new Account(Name = tag + '-B')
};
insert seeded;
Set<Id> createdIds = new Map<Id, Account>(seeded).keySet();

System.debug('System count: 0');
System.debug('User count: 0');
System.debug('Match: false');

Related drills

Try this drill free

You write the Apex yourself. ApexSensei runs it and tells you what passed and what did not.

‹ Single-row query: zero or many rows · Group by a parent field ›