DESCRIPTION
Let’s first understand “Setup Objects” and Non-setup objects.
Setup Objects
- The
Setup
object in Salesforce is a special object used internally to manage user access to Salesforce setup and configuration pages. It is not an actual object that can be queried or manipulated in the same way as standard or custom objects likeAccount
,Opportunity
, etc. Instead, the term “Setup” typically refers to the settings and administrative interface in Salesforce where administrators can configure various system-wide features. - So creating/updating User, Role, Profile, and Permission Set are considered as manipulating Setup objects.
Non-setup Objects
non-setup objects refer to objects that are part of the application data model and are used to store and manage business data. These are the objects that you and your users typically interact with on a day-to-day basis to handle records like customer information, sales opportunities, support cases, etc.
MIXED DML OPERATION PROBLEM
As we know setup objects (such as profiles, users, or roles) and non-setup objects (such as accounts, contacts, or custom objects) uses different databases which can cause errors or inconsistencies in the backend; also changing setup data can impact the whole platform, so keeping it separate from business data ensures the system runs smoothly without issues.
Key Reasons for Keeping Setup and Non-Setup Objects Separate:
- Different Databases for Stability:
- Setup objects (such as
User
,Profile
,Role
,ApexClass
) are part of the configuration layer of Salesforce, managing system-wide settings and metadata. - Non-setup objects (like
Account
,Contact
,Opportunity
,CustomObject
) deal with business data, which is the core of CRM operations. - These two sets of objects are stored in different databases or layers to ensure that changes to configuration settings (setup objects) don’t accidentally impact day-to-day operations involving business data (non-setup objects).
- Setup objects (such as
- Prevent Errors and Inconsistencies:
- Changing setup data (e.g., modifying profiles, permissions, or triggers) could inadvertently affect the way users interact with business data. For example, altering a profile’s permissions might restrict access to
Account
orOpportunity
objects. - By separating setup objects and non-setup objects, Salesforce reduces the chance of unexpected system errors or inconsistencies caused by these changes.
- Changing setup data (e.g., modifying profiles, permissions, or triggers) could inadvertently affect the way users interact with business data. For example, altering a profile’s permissions might restrict access to
- Impact of Setup Changes on the Entire Org:
- Setup object changes can affect the entire organization. For instance, updating a permission set could affect multiple users across various departments. Similarly, altering an Apex class or trigger could modify how data is processed for all records.
- Keeping this configuration data isolated ensures that critical platform settings can be managed carefully without causing widespread disruption to daily operations.
- Platform Performance and Scalability:
- Since setup data often requires less frequent updates but can have a broad impact, and business data (non-setup) is updated and queried frequently, separating them helps ensure that performance bottlenecks do not occur.
- By keeping the databases separate, Salesforce can optimize the performance of frequent business transactions without impacting the system’s ability to handle administrative and configuration changes.
- Transaction Handling and Security:
- Salesforce transactions involving business data (such as creating new leads, closing opportunities, or updating account information) follow a different transactional path than setup data (such as changing profiles or deploying metadata).
- By keeping these transactions separate, Salesforce ensures data consistency and security while minimizing the risk of one type of transaction impacting another.
- Deployment and Change Management:
- Setup objects are often deployed using the Metadata API, Change Sets, or Salesforce DX to manage changes in configuration and customization. This deployment is usually done in a controlled way to minimize the risk of disruption.
- Non-setup objects (business data) are managed through day-to-day CRUD operations by users and applications, and are not typically part of the deployment process.
- By separating the two, Salesforce ensures that deployments related to configuration (setup data) are handled differently from the ongoing management of business records, reducing the likelihood of system issues.
Example of Potential Errors from Mixing Setup and Non-Setup Data:
Another example would be modifying a Role
or Profile
that has permissions tied to accessing certain non-setup objects (like Opportunity
or Case
). A wrong configuration in these setup objects could suddenly restrict user access to critical business data, causing operational issues.
// Example: This will cause a mixed DML error User newUser = new User( LastName = 'Doe', Email = 'jdoe@example.com', Username = 'jdoe@example.com', ProfileId = '00e00000000XXXX', Alias = 'jdoe', TimeZoneSidKey = 'America/Los_Angeles', LocaleSidKey = 'en_US', EmailEncodingKey = 'UTF-8', LanguageLocaleKey = 'en_US' ); Account newAccount = new Account(Name = 'New Client Account'); // Attempting to insert both a User (setup object) and Account (non-setup object) in the same transaction insert newUser; insert newAccount; // This will throw a Mixed DML exception
SOLUTION: Use Asynchronous Processing
To work around this, separate the DML operations into different transactions using asynchronous methods such as:
- @future Methods
- Queueable Apex
- Batch Apex
Example Using @future
:
Here’s how to separate the setup and non-setup DML operations using the @future
method:
// Class to handle User creation asynchronously public class SetupObjectHandler { @future public static void createUserAsync(String lastName, String email, String username, Id profileId) { User newUser = new User( LastName = lastName, Email = email, Username = username, ProfileId = profileId, Alias = 'futureuser', TimeZoneSidKey = 'America/Los_Angeles', LocaleSidKey = 'en_US', EmailEncodingKey = 'UTF-8', LanguageLocaleKey = 'en_US' ); insert newUser; // Handle DML on setup object } } // Class to handle non-setup operations in the current transaction public class NonSetupObjectHandler { public static void createAccountAndUser() { Account newAccount = new Account(Name = 'New Client Account'); insert newAccount; // Handle DML on non-setup object // Now use future method to create User asynchronously SetupObjectHandler.createUserAsync('Doe', 'jdoe@example.com', 'jdoe@example.com', '00e00000000XXXX'); } }
Summary
When handling both setup and non-setup objects in Apex, it’s important to:
- Separate DML operations for setup and non-setup objects by using asynchronous methods like
@future
,Queueable
, orBatch Apex
. - Handle setup object operations in tests with
System.runAs()
to avoid Mixed DML errors. - Check permissions before attempting to create or modify setup objects.
- Use Metadata API for large-scale or bulk updates to configuration data.
By following these guidelines, you can ensure that your Apex code handles setup and non-setup object interactions safely and without triggering system errors or performance issues. Let me know if you’d like more specific examples or further clarification!