Table of Contents


Database Options Reference


Summary

This section provides a comprehensive reference for the DatabaseOptions class, which controls the behavior of database operations.

DatabaseOptions Class

DatabaseOptions controls how database operations (Create, Edit, Upsert, Delete) are executed.

Class Overview:

public class DatabaseOptions
{
    public bool IsApiMode { get; set; }
    public bool SystemMode { get; set; }
    public bool AllOrNone { get; set; }
    public bool TriggerUserEmail { get; set; }
    public bool PermanentDelete { get; set; }
    public string ExternalIdField { get; set; }
}

DatabaseOptions Properties

IsApiMode

Controls error handling behavior for database operations.

PropertyTypeDefaultDescription
IsApiModeboolfalseWhen true, returns errors in result objects; when false, throws exceptions

Usage:

// IsApiMode = true (recommended)
var result = Database.Create(account, new DatabaseOptions { IsApiMode = true });

if (result.HasError)
{
    // Handle errors from result
    foreach (var error in result.Errors)
    {
        SystemInfo.Debug($"{error.PropertyName}: {error.Message}");
    }
}

// IsApiMode = false (default - throws exceptions)
try
{
    var result = Database.Create(account);
}
catch (Exception ex)
{
    // Handle exception
    SystemInfo.Debug($"Error: {ex.Message}");
}

When to Use:

  • ✅ Always use IsApiMode = true for better error handling
  • ✅ Recommended for all database operations
  • ✅ Required for bulk operations where some records may fail
  • ❌ Avoid default behavior (exceptions) unless specifically needed

SystemMode

Executes database operations with system administrator privileges, bypassing user permissions and sharing rules.

PropertyTypeDefaultDescription
SystemModeboolfalseWhen true, bypasses all user permissions and sharing rules

Usage:

// Execute with system privileges
var result = Database.Create(account, new DatabaseOptions 
{ 
    SystemMode = true,
    IsApiMode = true 
});

// Execute with user permissions (default)
var result = Database.Create(account, new DatabaseOptions { IsApiMode = true });

Behavior:

  • When SystemMode = true:

    • User permissions are ignored
    • Sharing rules are bypassed
    • Record access is unrestricted
    • All records in database are accessible
    • Field-level security is bypassed
  • When SystemMode = false (default):

    • User permissions apply
    • Sharing rules are enforced
    • Only accessible records are visible
    • Field-level security applies

When to Use:

  • ✅ Automated system processes
  • ✅ System integrations
  • ✅ Administrative operations requiring full access
  • ✅ Background jobs and scheduled tasks
  • ❌ Never use for user-facing operations
  • ❌ Never use without explicit business justification
Warning: Always document why SystemMode = true is required. Misuse can create security vulnerabilities.

Examples:

// Automated cleanup process
public void AutomatedCleanupProcess()
{
    var oldRecords = Database.Query<Account>()
        .Where(f => f.LastActivityDate__c < DateTime.UtcNow.AddYears(-5))
        .ToListAsAdmin();
    
    // Delete with system privileges
    Database.Delete(oldRecords, new DatabaseOptions 
    { 
        SystemMode = true,
        IsApiMode = true 
    });
}

// System integration
public void SyncFromExternalSystem(List<ExternalAccount> externalAccounts)
{
    var accounts = ConvertToAccounts(externalAccounts);
    
    // Upsert with system privileges
    var results = Database.Upsert(accounts, new DatabaseOptions 
    { 
        SystemMode = true,
        ExternalIdField = "ExternalId__c",
        IsApiMode = true 
    });
}

AllOrNone

Controls transactional behavior for bulk operations.

PropertyTypeDefaultDescription
AllOrNoneboolfalseWhen true, all records must succeed or all fail together

Usage:

// Transactional mode - all succeed or all fail
var results = Database.Create(accounts, new DatabaseOptions 
{ 
    AllOrNone = true,
    IsApiMode = true 
});

if (results.Any(r => r.HasError))
{
    SystemInfo.Debug("Transaction failed - no records were created");
}
else
{
    SystemInfo.Debug("All records created successfully");
}

// Default mode - partial success allowed
var results = Database.Create(accounts, new DatabaseOptions { IsApiMode = true });

var successCount = results.Count(r => !r.HasError);
var errorCount = results.Count(r => r.HasError);
SystemInfo.Debug($"Created {successCount}, failed {errorCount}");

Behavior:

  • When AllOrNone = true:

    • All records processed in single transaction
    • If any record fails, entire operation rolls back
    • No records are created/updated/deleted if any fail
    • All results will have same status (all success or all error)
  • When AllOrNone = false (default):

    • Each record processed independently
    • Successful records are committed
    • Failed records are skipped
    • Partial success is possible

When to Use:

  • ✅ Related records that must be created together
  • ✅ Financial transactions requiring consistency
  • ✅ Data integrity requirements
  • ✅ When partial success is unacceptable
  • ❌ Large batch operations (may fail entire batch)
  • ❌ When partial success is acceptable

Examples:

// Order with line items - must all succeed
public SaveResult CreateOrderWithItems(Order order, List<OrderItem> items)
{
    // Create order
    var orderResult = Database.Create(order, new DatabaseOptions 
    { 
        AllOrNone = true,
        IsApiMode = true 
    });
    
    if (orderResult.HasError)
    {
        return orderResult;
    }
    
    // Link items to order
    foreach (var item in items)
    {
        item.OrderId = orderResult.Id;
    }
    
    // Create items - all must succeed
    var itemResults = Database.Create(items, new DatabaseOptions 
    { 
        AllOrNone = true,
        IsApiMode = true 
    });
    
    if (itemResults.Any(r => r.HasError))
    {
        // Rollback order if items fail
        Database.Delete(orderResult.Id, new DatabaseOptions { IsApiMode = true });
        
        SystemInfo.Debug("Order creation failed - all changes rolled back");
        return itemResults.First(r => r.HasError);
    }
    
    return orderResult;
}

TriggerUserEmail

Controls whether automated emails are sent to users during user record operations.

PropertyTypeDefaultDescription
TriggerUserEmailbooltrueWhen true, sends automated emails; when false, suppresses emails

Usage:

// Create user without sending welcome email
var user = new User
{
    Email = "newuser@example.com",
    FirstName = "Jane",
    LastName = "Doe"
};

var result = Database.Create(user, new DatabaseOptions 
{ 
    TriggerUserEmail = false,
    IsApiMode = true 
});

// Create user with welcome email (default)
var result = Database.Create(user, new DatabaseOptions { IsApiMode = true });

Affected Operations:

  • User creation (welcome/activation emails)
  • User updates (notification emails)
  • Password resets

When to Use:

  • ✅ Bulk user imports
  • ✅ User provisioning from external systems
  • ✅ Testing environments
  • ✅ User record updates that don't require notification
  • ❌ Single user creation when email is needed
  • ❌ Password reset operations requiring notification

Examples:

// Bulk user import without emails
public void ImportUsers(List<ExternalUser> externalUsers)
{
    var users = new List<User>();
    
    foreach (var ext in externalUsers)
    {
        users.Add(new User
        {
            Email = ext.Email,
            FirstName = ext.FirstName,
            LastName = ext.LastName
        });
    }
    
    // Create users without sending emails
    var results = Database.Create(users, new DatabaseOptions 
    { 
        TriggerUserEmail = false,
        IsApiMode = true 
    });
    
    SystemInfo.Debug($"Imported {results.Count(r => !r.HasError)} users");
}

PermanentDelete

Controls whether records are permanently deleted or moved to recycle bin.

PropertyTypeDefaultDescription
PermanentDeleteboolfalseWhen true, permanently deletes records; when false, soft deletes to recycle bin

Usage:

// Soft delete (default) - moves to recycle bin
var result = Database.Delete(accountId, new DatabaseOptions { IsApiMode = true });

// Permanent delete - removes completely
var result = Database.Delete(accountId, new DatabaseOptions 
{ 
    PermanentDelete = true,
    IsApiMode = true 
});

Behavior:

  • When PermanentDelete = true:

    • Records are permanently removed
    • Records cannot be restored
    • Related records may be affected
    • Use with extreme caution
  • When PermanentDelete = false (default):

    • Records moved to recycle bin
    • Records marked as IsDeleted = true
    • Records can be restored
    • Records excluded from standard queries

When to Use:

  • ✅ Removing test data from production
  • ✅ Cleaning up duplicate records
  • ✅ Data retention policy compliance
  • ✅ Purging old archived data
  • ❌ Standard record deletion
  • ❌ Records that may need restoration
  • ❌ Unless specifically required
Warning: Permanent delete cannot be undone. Always use with extreme caution.

Examples:

// Remove test data permanently
public void CleanupTestData()
{
    var testRecords = Database.Query<Account>()
        .Where(f => f.Type == "Test" && f.CreatedOn < DateTime.UtcNow.AddDays(-90))
        .ToList();
    
    if (testRecords.Count > 0)
    {
        SystemInfo.Debug($"WARNING: Permanently deleting {testRecords.Count} test records");
        
        var results = Database.Delete(testRecords, new DatabaseOptions 
        { 
            PermanentDelete = true,
            IsApiMode = true 
        });
    }
}

ExternalIdField

Specifies the field to use for matching records in upsert operations.

PropertyTypeDefaultDescription
ExternalIdFieldstringnullField name to use for matching existing records during upsert

Usage:

// Upsert by external ID field
var account = new Account
{
    ExternalId__c = "EXT-12345",
    Name = "Partner Company",
    Type = "Partner"
};

var result = Database.Upsert(account, new DatabaseOptions 
{ 
    ExternalIdField = "ExternalId__c",
    IsApiMode = true 
});

// Upsert by email
var contact = new Contact
{
    Email = "john@example.com",
    FirstName = "John",
    LastName = "Smith"
};

var result = Database.Upsert(contact, new DatabaseOptions 
{ 
    ExternalIdField = "Email",
    IsApiMode = true 
});

Behavior:

  • If record with matching external ID value exists, it updates
  • If no match found, it creates new record
  • External ID field must be unique
  • External ID field must be indexed for performance

Requirements:

  • Field must exist on the entity
  • Field should be marked as unique
  • Field should be indexed
  • Field value must not be null

When to Use:

  • ✅ Data synchronization from external systems
  • ✅ Import operations with external identifiers
  • ✅ API integrations
  • ✅ When record existence is unknown
  • ❌ When using record ID for matching
  • ❌ When operation type (create/update) is known

Common External ID Fields:

  • ExternalId__c - Generic external system ID
  • Email - Email address (Contacts, Users)
  • ProductCode - Product SKU
  • OrderNumber__c - Order number
  • InvoiceNumber__c - Invoice number

Examples:

// Sync products from external catalog
public void SyncProducts(List<ExternalProduct> externalProducts)
{
    var products = new List<Product>();
    
    foreach (var ext in externalProducts)
    {
        products.Add(new Product
        {
            ProductCode = ext.SKU,  // External ID
            Name = ext.Name,
            Price__c = ext.Price
        });
    }
    
    var results = Database.Upsert(products, new DatabaseOptions 
    { 
        ExternalIdField = "ProductCode",
        IsApiMode = true 
    });
    
    var inserted = results.Count(r => !r.HasError && r.IsInsert);
    var updated = results.Count(r => !r.HasError && !r.IsInsert);
    
    SystemInfo.Debug($"Synced products: {inserted} new, {updated} updated");
}

Combined Options Examples

Complete Create with All Options:

var results = Database.Create(accounts, new DatabaseOptions
{
    IsApiMode = true,           // Return errors in results
    SystemMode = false,         // Use user permissions
    AllOrNone = true,           // All succeed or all fail
    TriggerUserEmail = true     // Send automated emails
});

Complete Upsert with All Options:

var results = Database.Upsert(contacts, new DatabaseOptions
{
    ExternalIdField = "Email",  // Match on email
    IsApiMode = true,           // Return errors in results
    SystemMode = false,         // Use user permissions
    AllOrNone = false           // Allow partial success
});

Complete Delete with All Options:

var results = Database.Delete(accounts, new DatabaseOptions
{
    IsApiMode = true,           // Return errors in results
    SystemMode = false,         // Use user permissions
    AllOrNone = true,           // All succeed or all fail
    PermanentDelete = false     // Soft delete to recycle bin
});

Best Practices for Database Options

Always use IsApiMode = true

var result = Database.Create(account, new DatabaseOptions { IsApiMode = true });

Document SystemMode usage

// JUSTIFICATION: Automated nightly cleanup process requires system access
var results = Database.Delete(oldRecords, new DatabaseOptions 
{ 
    SystemMode = true,
    IsApiMode = true 
});

Use AllOrNone for related records

// Create order and items together
var results = Database.Create(orderItems, new DatabaseOptions 
{ 
    AllOrNone = true,
    IsApiMode = true 
});

Soft delete by default

// Allow recovery
var result = Database.Delete(accountId, new DatabaseOptions { IsApiMode = true });

Avoid SystemMode without justification

// ❌ BAD - No justification
var result = Database.Create(account, new DatabaseOptions { SystemMode = true });

Avoid PermanentDelete unless required

// ❌ BAD - Unnecessary permanent delete
var result = Database.Delete(accountId, new DatabaseOptions 
{ 
    PermanentDelete = true,
    IsApiMode = true 
});
Last updated on 1/8/2026

Attachments