DML Operations & Database Methods
📖 Concept
DML (Data Manipulation Language) operations are how you create, update, and delete records in Salesforce. Understanding the nuances between DML statements and Database methods is essential.
DML Statements (simple):
insert records; — Create new records
update records; — Modify existing records
upsert records; — Insert or update (based on external ID or record ID)
delete records; — Soft delete (goes to Recycle Bin)
undelete records; — Restore from Recycle Bin
merge records; — Merge duplicate records
Database Methods (advanced):
Database.insert(records, allOrNone)
Database.update(records, allOrNone)
Database.upsert(records, externalIdField, allOrNone)
Database.delete(records, allOrNone)
Database.undelete(records, allOrNone)
Key difference — allOrNone parameter:
- DML statements: All or nothing (one failure rolls back everything)
- Database methods with
allOrNone = false: Partial success (successful records are committed, failed ones return errors)
Governor limits for DML:
- 150 DML statements per transaction
- 10,000 total DML rows per transaction
- These are cumulative across all operations in the transaction
Upsert — the powerful hybrid: Upsert checks if the record exists:
- If it has an Id → update
- If it doesn't → insert
- Can also match on External ID fields (useful for integration)
Best practices:
- Collect all records in a List, then perform ONE DML operation
- Use Database methods with
allOrNone = falsefor bulk operations where partial success is acceptable - Always handle DmlException in try-catch blocks
- Use
Database.SaveResultto check individual record outcomes - Consider using
Database.setSavepoint()andDatabase.rollback()for transaction control
💻 Code Example
1// DML Operations — Complete Guide23public class DMLExamples {45 // 1. Basic DML statements6 public static void basicDML() {7 // INSERT8 Account acc = new Account(Name = 'Acme Corp', Industry = 'Technology');9 insert acc;10 System.debug('New Account Id: ' + acc.Id); // Id populated after insert1112 // UPDATE13 acc.AnnualRevenue = 5000000;14 update acc;1516 // UPSERT — Insert or Update based on External ID17 Account upsertAcc = new Account(18 External_Id__c = 'EXT-001', // External ID field19 Name = 'Upserted Account',20 Industry = 'Finance'21 );22 upsert upsertAcc External_Id__c; // Match on External_Id__c2324 // DELETE (soft delete — goes to Recycle Bin)25 delete acc;2627 // UNDELETE (restore from Recycle Bin)28 undelete acc;29 }3031 // 2. Bulk DML (proper pattern)32 public static void bulkDML(List<Contact> newContacts) {33 // GOOD — Single DML for entire list34 insert newContacts; // Handles up to 10,000 records3536 // BAD — DML inside loop (hits 150 DML limit at 150 records)37 // for (Contact c : newContacts) {38 // insert c; // ❌ Each iteration is 1 DML statement!39 // }40 }4142 // 3. Database methods with partial success43 public static void partialSuccessDML(List<Account> accounts) {44 // allOrNone = false: successful records are saved,45 // failed records return errors46 Database.SaveResult[] results = Database.insert(accounts, false);4748 List<Account> successRecords = new List<Account>();49 List<String> errorMessages = new List<String>();5051 for (Integer i = 0; i < results.size(); i++) {52 Database.SaveResult sr = results[i];53 if (sr.isSuccess()) {54 successRecords.add(accounts[i]);55 } else {56 for (Database.Error err : sr.getErrors()) {57 errorMessages.add(58 'Record [' + i + '] ' + accounts[i].Name +59 ': ' + err.getMessage() +60 ' (Fields: ' + err.getFields() + ')'61 );62 }63 }64 }6566 System.debug('Inserted: ' + successRecords.size());67 System.debug('Errors: ' + errorMessages.size());68 for (String msg : errorMessages) {69 System.debug('ERROR: ' + msg);70 }71 }7273 // 4. Upsert with External ID (integration pattern)74 public static void upsertFromExternalSystem(List<Map<String, Object>> externalData) {75 List<Account> accountsToUpsert = new List<Account>();7677 for (Map<String, Object> data : externalData) {78 accountsToUpsert.add(new Account(79 External_Id__c = (String) data.get('externalId'),80 Name = (String) data.get('name'),81 Industry = (String) data.get('industry'),82 AnnualRevenue = (Decimal) data.get('revenue')83 ));84 }8586 // Upsert matches on External_Id__c87 // - If External_Id__c exists → UPDATE88 // - If External_Id__c doesn't exist → INSERT89 Database.UpsertResult[] results = Database.upsert(90 accountsToUpsert, Account.External_Id__c, false91 );9293 for (Database.UpsertResult ur : results) {94 if (ur.isSuccess()) {95 if (ur.isCreated()) {96 System.debug('INSERTED: ' + ur.getId());97 } else {98 System.debug('UPDATED: ' + ur.getId());99 }100 }101 }102 }103104 // 5. Transaction control with Savepoints105 public static void transactionControl() {106 Savepoint sp = Database.setSavepoint();107108 try {109 Account acc = new Account(Name = 'Test Transaction');110 insert acc;111112 Contact con = new Contact(113 FirstName = 'Test',114 LastName = 'Contact',115 AccountId = acc.Id116 );117 insert con;118119 // Simulate a failure120 if (someCondition) {121 throw new CustomException('Business rule violated');122 }123124 // If we get here, both records are committed125 } catch (Exception e) {126 // Rollback BOTH insert operations127 Database.rollback(sp);128 System.debug('Transaction rolled back: ' + e.getMessage());129 }130 }131132 // 6. Merge — Combine duplicate records133 public static void mergeDuplicates(Id masterAccountId, Id duplicateAccountId) {134 Account master = [SELECT Id FROM Account WHERE Id = :masterAccountId];135 Account duplicate = [SELECT Id FROM Account WHERE Id = :duplicateAccountId];136137 // Merge transfers all child records (Contacts, Opportunities, etc.)138 // from duplicate to master, then deletes the duplicate139 merge master duplicate;140141 // Can merge up to 3 records at once142 // merge master new List<Account>{dup1, dup2};143 }144145 // 7. Mixed DML — System and Setup objects146 // You CANNOT mix DML on setup objects (User, Profile, PermissionSet)147 // with non-setup objects (Account, Contact) in the same transaction148 public static void handleMixedDML() {149 // This would FAIL:150 // Account acc = new Account(Name = 'Test');151 // insert acc;152 // User u = [SELECT Id FROM User LIMIT 1];153 // u.LastName = 'Updated';154 // update u; // ❌ MIXED_DML_OPERATION error!155156 // SOLUTION: Use @future or System.runAs()157 // Or separate the operations into different transactions158 }159}
🏋️ Practice Exercise
DML Practice Exercises:
- Write a method that inserts 500 Account records in a single DML operation and verify the count
- Implement a partial-success insert that logs all errors to a custom Error_Log__c object
- Use Database.setSavepoint() to implement a multi-step operation with rollback on any failure
- Write an upsert operation that syncs data from an external system using External ID
- Implement a merge operation that combines 3 duplicate Contacts into one master record
- Handle the Mixed DML Operation error — insert a User and an Account in the same test method
- Write a method that deletes records and then undeletes them, verifying data integrity
- Create a utility that performs bulk updates in chunks of 200 to handle lists larger than 10,000
- Write error handling that captures Database.Error details and creates human-readable error messages
- Implement an "undo" feature using Savepoints that rolls back the last 3 operations
⚠️ Common Mistakes
Performing DML inside loops — 'insert record;' inside a for-loop hits the 150 DML statement limit. Always collect records in a List and do one DML outside the loop
Not handling DML exceptions — a single bad record in 'insert records;' rolls back ALL records. Use Database.insert(records, false) for partial success
Mixing setup and non-setup DML — inserting a User and an Account in the same transaction throws MIXED_DML_OPERATION. Separate them with @future or System.runAs()
Not checking Database.SaveResult — always iterate results to log errors, especially with allOrNone = false
Exceeding the 10,000 DML rows limit — if you need to update more than 10,000 records, use Batch Apex
💼 Interview Questions
🎤 Mock Interview
Mock interview is powered by AI for DML Operations & Database Methods. Login to unlock this feature.