ApexSensei

Drills DML operations

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. undelete takes a list, so wrap a single record in new 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:

  1. undelete should be present so the restore is a true undelete.
  2. ALL ROWS should be present on the bin query.
  3. After delete active: 0 should be printed from the active count after delete.
  4. After delete in bin: 1 should be printed from the ALL ROWS count after delete.
  5. After undelete active: 1 should be printed from the active count after undelete.
  6. After undelete in bin: 0 should be printed from the ALL ROWS count after undelete.

Starter code

String tag = 'AS-D311-' + UserInfo.getUserId() + '-' +
    String.valueOf(Datetime.now().getTime());
Account acct = new Account(Name = tag);
insert acct;

Related drills

Try this drill free

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 ›