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);