DML & Database Methods
DML statements are all-or-none: if one record fails, the entire statement fails with a DmlException and nothing is saved.
17.1 DML statements
Create records; populates Id Modify records (must have Id)
Insert or update, matching on Id or an External ID field Move records to the Recycle Bin
Restore from the Recycle Bin (query with ALL ROWS) Merge up to 3 records of the same type (Account, Contact, Lead, Case, Individual)
DML statements are all-or-none: if one record fails, the entire statement fails with a DmlException and nothing is saved.
List<Contact> contacts = new List<Contact>();
for (Integer i = 0; i < 200; i++) {
contacts.add(new Contact(LastName = 'Bulk ' + i));
}
insert contacts; // ONE DML statement for 200 records
for (Contact c : contacts) c.Title = 'Customer';
update contacts;
// upsert on an External ID field
List<Account> fromErp = new List<Account>{
new Account(Name = 'Globex', ERP_Id__c = 'ERP-100'),
new Account(Name = 'Initech', ERP_Id__c = 'ERP-200')
};
upsert fromErp Account.ERP_Id__c;
// insert parent and child in one statement using an External ID reference
Contact child = new Contact(LastName = 'Ref', Account = new Account(ERP_Id__c = 'ERP-100'));
insert child;
delete [SELECT Id FROM Contact WHERE LastName LIKE 'Bulk %'];
undelete [SELECT Id FROM Contact WHERE IsDeleted = true AND LastName LIKE 'Bulk %' ALL ROWS];
Account master = [SELECT Id FROM Account WHERE Name = 'Globex' LIMIT 1];
Account dup = [SELECT Id FROM Account WHERE Name = 'Globex Inc' LIMIT 1];
merge master dup;17.2 Database class methods (partial success)
Database.insert/update/upsert/delete/undelete/merge accept an allOrNone flag. With false, valid records are saved and failures are reported in result objects:
Database.insert / update Database.UpsertResult[] (isCreated())
Database.EmptyRecycleBinResult[] — permanently deletes
List<Account> accs = new List<Account>{
new Account(Name = 'Valid One'),
new Account(), // missing required Name → fails
new Account(Name = 'Valid Two')
};
Database.SaveResult[] results = Database.insert(accs, false);
for (Integer i = 0; i < results.size(); i++) {
Database.SaveResult sr = results[i];
if (sr.isSuccess()) {
System.debug('Inserted ' + sr.getId());
} else {
for (Database.Error err : sr.getErrors()) {
System.debug('Row ' + i + ' failed: ' + err.getStatusCode() + ' ' + err.getMessage()
+ ' fields: ' + err.getFields());
}
}
}17.3 DML options and user mode
Database.DMLOptions opts = new Database.DMLOptions();
opts.assignmentRuleHeader.useDefaultRule = true; // run lead/case assignment rules
opts.duplicateRuleHeader.allowSave = true; // bypass duplicate-rule alerts
opts.optAllOrNone = false;
Database.insert(leads, opts);
// user-mode DML: enforce CRUD, FLS, and sharing of the running user
insert as user contacts;
update as user contacts;
Database.insert(contacts, false, AccessLevel.USER_MODE);
// explicit system mode
insert as system contacts;17.4 Savepoints and rollback
Facts: each setSavepoint and rollback counts against the DML statement limit; IDs assigned to records inserted after the savepoint are not cleared from your variables after rollback (re-inserting them fails — clone without IDs); savepoints cannot be used across transactions.
Savepoint sp = Database.setSavepoint();
try {
Account a = new Account(Name = 'Parent');
insert a;
insert new Contact(LastName = 'Child', AccountId = a.Id);
insert new Opportunity(Name = 'Deal', AccountId = a.Id, StageName = 'Prospecting',
CloseDate = Date.today().addDays(30));
} catch (DmlException e) {
Database.rollback(sp); // undo everything since the savepoint
// ApplicationException is a custom exception (public class ApplicationException extends Exception {})
throw new ApplicationException('Onboarding failed: ' + e.getDmlMessage(0), e);
}17.5 DmlException details
try {
insert new List<Contact>{ new Contact(), new Contact() };
} catch (DmlException e) {
for (Integer i = 0; i < e.getNumDml(); i++) {
System.debug(e.getDmlIndex(i) + ': ' + e.getDmlType(i) + ' ' + e.getDmlMessage(i));
}
}17.6 Mixed DML
You can't perform DML on setup objects (User, Group, GroupMember, PermissionSetAssignment, QueueSObject, …) and non-setup objects (Account, …) in the same transaction — MIXED_DML_OPERATION. Solutions: move one part to a @future/Queueable method, or in tests wrap setup DML in System.runAs(...).