Prevent duplicate field name errors in managed Apex SOQL queries when your package
fields and a subscriber’s custom fields share the same name. Set the
explicitNamespace property on a Database.QueryOptions object
and pass it as a bind variable in the SOQL SET OPTIONS clause. Without
requiring an explicit namespace, Apex interprets both fields as belonging to your package
namespace, failing the unique field name requirement enforced in API version 34.0 and
later.
Where: This feature is available in Lightning Experience and Salesforce Classic in Enterprise, Performance, Unlimited, and Developer editions.
Why: Field name collisions between managed packages and subscriber orgs can cause
package failures. Previously, there was no mechanism for managed Apex code to explicitly
control namespace resolution in SOQL. For example, if a managed package with the namespace
ExPackageNS had an Age__c field and a subscriber created a
custom field Age__c, queries for both fields simultaneously resulted in a
duplicate field name error. Additionally, there was no mechanism for the managed Apex code to
query for just the subscriber’s field. Now, by setting the explicitNamespace
property as a query option, the package field resolves to ExPackageNS__Age__c
instead. Queries without the SET OPTIONS clause preserve their existing
behavior, so the change is backward compatible.
How: Create a Database.QueryOptions object through its builder methods,
including .withExplicitNamespace(true). Pass the object as a bind variable in
the SET OPTIONS clause, and then pass the query to
Database.query() or Database.queryWithBinds().
Here’s a dynamic SOQL query created with Database.query().
Database.QueryOptions opts = Database.QueryOptions.builder()
.withExplicitNamespace(true)
.build();
List<Account> results = Database.query(
'SELECT Id, Name, Age__c, ExPackageNS__Age__c FROM Account SET OPTIONS :opts',
AccessLevel.USER_MODE);
Here’s a dynamic SOQL query created with Database.queryWithBinds().
Database.QueryOptions opts = Database.QueryOptions.builder()
.withExplicitNamespace(true)
.build();
List<Account> results = Database.queryWithBinds(
'SELECT Id, Name, Age__c, ExPackageNS__Age__c FROM Account SET OPTIONS :opts',
new Map<String, Object>{ 'opts' => opts },
AccessLevel.USER_MODE);