Table of Contents


Creating Records (INSERT Operations)


Summary

This section covers all methods for inserting new records into the database, including single record creation, bulk operations, understanding SaveResult, error handling, and create options.

Single Record Insert

Use Database.Create() to insert a single record into the database.

Basic Single Record Create:

// Create a new account
var account = new Account
{
    Name = "Partner Company",
    Type = "Partner",
    Industry = "Technology"
};

Database.Create(account);

Create with All Required Fields:

// Ensure all required fields are populated
var contact = new Contact
{
    FirstName = "John",
    LastName = "Smith",
    Email = "john.smith@example.com",
    AccountId = accountId  // Link to account
};

Database.Create(contact);

ID Generation:

// System automatically generates ID if not provided
var account = new Account
{
    Name = "New Account",
    Type = "Customer"
};

Database.Create(account);

// ID is now available
SystemInfo.Debug($"Generated ID: {result.Id}");
SystemInfo.Debug($"Same ID on object: {account.Id}");

// Or manually generate ID before create
var manualAccount = new Account
{
    Id = Database.NewId(Account.KeyPrefix),
    Name = "Manual ID Account",
    Type = "Partner"
};

Database.Create(manualAccount);

Create with Related Records:

// Create account first
var account = new Account
{
    Name = "Partner Company",
    Type = "Partner"
};

Database.Create(account);

// Create contact linked to new account
var contact = new Contact
{
    FirstName = "John",
    LastName = "Smith",
    Email = "john@example.com",
    AccountId = accountResult.Id  // Link to newly created account
};

Database.Create(contact);

Bulk Insert

Always use bulk insert methods when creating multiple records. Never perform database operations in loops.

Basic Bulk Insert:

// Create multiple accounts in a single operation
var accounts = new List<Account>
{
    new Account { Name = "Account 1", Type = "Partner" },
    new Account { Name = "Account 2", Type = "Customer" },
    new Account { Name = "Account 3", Type = "Vendor" }
};

Database.Create(accounts);

Bulk Insert with Loop Preparation:

// ✅ GOOD: Prepare list, then single bulk insert
var contactsToCreate = new List<Contact>();

foreach (var csvRow in csvData)
{
    contactsToCreate.Add(new Contact
    {
        FirstName = csvRow.FirstName,
        LastName = csvRow.LastName,
        Email = csvRow.Email,
        AccountId = csvRow.AccountId
    });
}

// Single bulk operation
Database.Create(contactsToCreate);

// ❌ BAD: Database operation in loop
foreach (var csvRow in csvData)
{
    var contact = new Contact
    {
        FirstName = csvRow.FirstName,
        LastName = csvRow.LastName,
        Email = csvRow.Email
    };
    
    Database.Create(contact);  // Multiple round-trips - very poor performance
}

Bulk Insert with Result Processing:

var accounts = new List<Account>
{
    new Account { Name = "Account 1", Type = "Partner" },
    new Account { Name = "", Type = "Customer" },  // Invalid - missing Name
    new Account { Name = "Account 3", Type = "Vendor" }
};

Database.Create(accounts);

Understanding SaveResult

The SaveResult class contains detailed information about create operations.

SaveResult Properties:

public class SaveResult
{
    public string Id { get; set; }              // ID of created record
    public bool HasError { get; set; }          // True if operation failed
    public List<Error> Errors { get; set; }     // Error details
    public DateTime? Timestamp { get; set; }    // Operation timestamp
}

Using Result ID:

// Create account and immediately use its ID
var account = new Account { Name = "Partner Company", Type = "Partner" };
Database.Create(account);

// Use the new ID to create related record
var contact = new Contact
{
    FirstName = "John",
    LastName = "Smith",
    AccountId = accountResult.Id  // Use result ID
};
    
Database.Create(contact);

Bulk Results Processing:

var accounts = new List<Account>
{
    new Account { Name = "Account 1", Type = "Partner" },
    new Account { Name = "Account 2", Type = "Customer" },
    new Account { Name = "Account 3", Type = "Vendor" }
};

Database.Create(accounts);

// Check if all succeeded
bool allSucceeded = results.All(r => !r.HasError);

if (allSucceeded)
{
    SystemInfo.Debug("All accounts created successfully");
}
else
{
    // Process individual results
    for (int i = 0; i < results.Count(); i++)
    {
        var result = results.ElementAt(i);
        var account = accounts[i];
        
        if (result.HasError)
        {
            SystemInfo.Debug($"Failed to create '{account.Name}': {result.Errors[0].Message}");
        }
        else
        {
            SystemInfo.Debug($"Created '{account.Name}' with ID: {result.Id}");
        }
    }
}

Error Handling

Proper error handling ensures data integrity and provides meaningful feedback.

Exception Mode (IsApiMode = false - default - recommended):

try
{
    var account = new Account { Name = "", Type = "Partner" };  // Invalid
    var result = Database.Create(account);  // Throws exception
    
    SystemInfo.Debug("Account created");
}
catch (DatabaseException ex)
{
    SystemInfo.Debug($"Create failed: {ex.Message}");
    // Handle exception appropriately
}

Result Mode (IsApiMode = true):

var account = new Account { Name = "", Type = "Partner" };  // Invalid
var result = Database.Create(account, new DatabaseOptions { IsApiMode = true });

if (result.HasError)
{
    // Handle errors without try-catch
    foreach (var error in result.Errors)
    {
        SystemInfo.Debug($"Validation error on {error.PropertyName}: {error.Message}");
    }
}
else
{
    SystemInfo.Debug($"Account created: {result.Id}");
}

Common Validation Errors:

// Required field missing
var account = new Account { Type = "Partner" };  // Missing Name
var result = Database.Create(account, new DatabaseOptions { IsApiMode = true });
// Error: PropertyName = "Name", Message = "Name is required"

// Invalid field value
var contact = new Contact 
{ 
    FirstName = "John", 
    LastName = "Smith", 
    Email = "invalid-email" 
};
var result = Database.Create(contact, new DatabaseOptions { IsApiMode = true });
// Error: PropertyName = "Email", Message = "Invalid email format"

// Duplicate unique value
var account = new Account 
{ 
    Name = "Test", 
    ExternalId__c = "EXISTING-ID" 
};
var result = Database.Create(account, new DatabaseOptions { IsApiMode = true });
// Error: PropertyName = "ExternalId__c", Message = "Duplicate external ID"

Controller Error Handling With IsApiMode = true:

[HttpPost]
public ActionResponse CreateAccount(Account model)
{
    var result = Database.Create(model, new DatabaseOptions { IsApiMode = true });
    
    if (result.HasError)
    {
        // Add errors to ModelState for display
        foreach (var error in result.Errors)
        {
            if (!string.IsNullOrEmpty(error.PropertyName))
            {
                ModelState.AddModelError(error.PropertyName, error.Message);
            }
            else
            {
                ModelState.AddModelError("", error.Message);
            }
        }
        
        return View(model);
    }
    
    AspxPage.AddMessage("Account created successfully!");
    return RedirectToAction("Details", new { id = result.Id });
}

Bulk Error Collection With IsApiMode = true::

public class ImportResult
{
    public int TotalRecords { get; set; }
    public int SuccessCount { get; set; }
    public int ErrorCount { get; set; }
    public List<string> Errors { get; set; }
}

public ImportResult ImportAccounts(List<Account> accounts)
{
    var results = Database.Create(accounts, new DatabaseOptions { IsApiMode = true });
    
    var importResult = new ImportResult
    {
        TotalRecords = accounts.Count,
        SuccessCount = 0,
        ErrorCount = 0,
        Errors = new List<string>()
    };
    
    for (int i = 0; i < results.Count(); i++)
    {
        var result = results.ElementAt(i);
        var account = accounts[i];
        
        if (result.HasError)
        {
            importResult.ErrorCount++;
            importResult.Errors.Add($"Row {i + 1} - {account.Name}: {result.Errors[0].Message}");
        }
        else
        {
            importResult.SuccessCount++;
        }
    }
    
    return importResult;
}

Create Options (DatabaseOptions)

DatabaseOptions controls create operation behavior.

IsApiMode:

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

if (result.HasError)
{
    // Handle errors in result
}

// Throw exceptions on error (default)
try
{
    var result = Database.Create(account);
}
catch (Exception ex)
{
    // Handle exception
}

SystemMode:

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

// Use SystemMode only when necessary:
// - Automated processes
// - System integrations
// - Administrative operations
Warning: Always document why SystemMode = true is required.

AllOrNone (Transactional Mode):

// All records must succeed or all fail
var accounts = new List<Account>
{
    new Account { Name = "Account 1", Type = "Partner" },
    new Account { Name = "", Type = "Customer" },  // Invalid
    new Account { Name = "Account 3", Type = "Vendor" }
};

Database.Create(accounts, new DatabaseOptions 
{ 
    AllOrNone = true
});

TriggerUserEmail:

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

var result = Database.Create(user, new DatabaseOptions 
{ 
    TriggerUserEmail = false,  // Don't send email
});

// Create user with activation email (default)
Database.Create(user);

Combined Options:

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

Create Operation Examples

Create with Validation:

public void CreateAccount(string name, string type, string industry)
{
    // Validate before create
    if (string.IsNullOrWhiteSpace(name))
    {
        SystemInfo.Debug("Account name is required");
        return null;
    }
    
    if (string.IsNullOrWhiteSpace(type))
    {
        SystemInfo.Debug("Account type is required");
        return null;
    }
    
    var account = new Account
    {
        Name = name,
        Type = type,
        Industry = industry
    };
    
    Database.Create(account);
}

Create with Related Records:

public void CreateAccountWithContacts(Account account, List<Contact> contacts)
{
    // Create account first
    var accountResult = Database.Create(account, new DatabaseOptions { IsApiMode = true });
    
    if (accountResult.HasError)
    {
        SystemInfo.Debug($"Failed to create account: {accountResult.Errors[0].Message}");
        return;
    }
    
    // Link contacts to new account
    foreach (var contact in contacts)
    {
        contact.AccountId = accountResult.Id;
    }
    
    // Create contacts
    Database.Create(contacts);
}

Import Pattern:

public void ImportAccountsFromCSV(List<CsvRow> csvData)
{
    // Prepare accounts (no database calls in loop)
    var accountsToCreate = new List<Account>();
    
    foreach (var row in csvData)
    {
        accountsToCreate.Add(new Account
        {
            Name = row.Name,
            Type = row.Type,
            Industry = row.Industry,
            AnnualRevenue = row.Revenue
        });
    }
    
    // Single bulk create
    Database.Create(accountsToCreate);
}

Best Practices for Creating Records

Use bulk operations for multiple records

// ✅ GOOD
Database.Create(accounts);

// ❌ BAD
foreach (var account in accounts)
{
    Database.Create(account);
}

Validate data before database operations

if (string.IsNullOrEmpty(account.Name))
{
    SystemInfo.Debug("Validation failed: Name is required");
    return;
}

Database.Create(account);

Check HasError and log errors

if (result.HasError)
{
    foreach (var error in result.Errors)
    {
        SystemInfo.Debug($"Create error - {error.PropertyName}: {error.Message}");
    }
}

Use AllOrNone for transactional integrity

var results = Database.Create(relatedRecords, new DatabaseOptions 
{ 
    AllOrNone = true,
});

Never perform database operations in loops

// ❌ VERY BAD
foreach (var account in accounts)
{
    Database.Create(account);  // Multiple database calls
}

// ✅ GOOD
Database.Create(accounts);

 

Last updated on 1/8/2026

Attachments