Undelete from the Recycle Bin
DML operations · Intermediate · 12 min · Runs in your Salesforce Developer org · Apex Path
A `delete` is a soft delete: the row moves to the Recycle Bin and `undelete` can bring it back with the same Id. Insert, delete, then undelete a tagged Account, and prove it is back in the active set. Query the bin with `ALL ROWS`; a plain query sees only active rows.
Lesson
Why this matters
A soft delete in Salesforce is not final. The row moves to the Recycle Bin for 15 days, keeps its Id, and can be restored with undelete. Support scripts and bulk-fix jobs rely on this to recover from a bad delete without re-creating records.
The smallest working example
Account acct = new Account(Name = 'Acme');
insert acct;
delete acct;
undelete new List<Account>{ acct };
After delete, acct.Id still works. undelete restores the same row with the same Id.
Name the parts
- **
delete acct** is a soft delete. The row moves to the Recycle Bin; a plain query no longer finds it. - **
undelete new List<Account>{ acct }** restores the row.undeletetakes a list, so wrap a single record innew List<Account>{ ... }. - **
WHERE Id = :savedId** on a plain query sees only active rows. - **
AND IsDeleted = true ALL ROWS** at the end of a SOQL query includes soft-deleted rows, so you can prove a row is sitting in the bin.
A common wrong version
delete acct;
Account replacement = new Account(Id = acct.Id, Name = 'Acme');
insert replacement;
You cannot insert with an Id already set; this throws. Even without that, re-inserting creates a new row with a different Id, so references on child records break.
The fix
Use undelete, which brings the exact same row back with the same Id:
undelete new List<Account>{ acct };
Now you try
Starter already inserts the Account. Delete it, run two counts (active and bin), undelete, then run both counts again. Print After delete active:, After delete in bin:, After undelete active: and After undelete in bin: in that order.
Learn more
The challenge
Insert, delete, then undelete one tagged Account and prove where it is at each step.
Examples:
- After
insert→ active count 1 - After
delete→ active count 0, bin count 1 - After
undelete→ active count 1, bin count 0
Requirements:
undeleteshould be present so the restore is a true undelete.ALL ROWSshould be present on the bin query.After delete active: 0should be printed from the active count afterdelete.After delete in bin: 1should be printed from theALL ROWScount afterdelete.After undelete active: 1should be printed from the active count afterundelete.After undelete in bin: 0should be printed from theALL ROWScount afterundelete.
Starter code
String tag = 'AS-D311-' + UserInfo.getUserId() + '-' +
String.valueOf(Datetime.now().getTime());
Account acct = new Account(Name = tag);
insert acct;
Related drills
- Catch a DmlException and read its details
- Roll back parent and children on a child failure
- Merge duplicate Accounts
You write the Apex yourself. ApexSensei runs it and tells you what passed and what did not.
‹ Catch a DmlException and read its details · Roll back parent and children on a child failure ›