Recycle Bin in Dataverse

Finally, the long-awaited feature is now available in sandbox environments – a record recycle bin. There have been many cases, when users deleted some records by mistake and it wasn’t possible to recover them.

Now, it will be possible to enable the recycle bin and store such records for a given period, up to 30 days, before they are permanently deleted.

Setup

Let’s set up our Recycle Bin. Firstly, let’s visit Power Platform admin center, then go to environment’s settings. Next, in Product -> Features section, at the bottom of the screen, there will be a new preview feature.

As you can see, apart from enabling feature, the administrator is also able to set the default recovery time interval.

This interval can be also set for each table separately in the Restore Deleted Records Configuration (schema name: recyclebinconfig) entity. 

Enabled tables

There are some limitations, and not all tables are enabled for restore. You can find a list of incompatible tables here.

Most of the configuration is stored in the Restore Deleted Records Configuration entity.

Each table has a definition with reference to metadata, default cleanup interval (if the value is set to -1, then the environment’s default value is used) and status. To disable the Recycle Bin for a particular entity, you have to deactivate table’s record (set statecode to 1 and statuscode to 2).

If the feature is enabled and you add your new custom entity, it will also be enabled for deleted records recovery. The same applies to custom columns on existing entities.

Restore

We’ve set up everything, so now let’s recover some test records. After deleting data that is enabled for the recycle bin, it should appear in the View Deleted Records section.

Additionally, you can add the Deleted Item Reference entity to your Model Driven App to see deleted data.

As visible on the screen below, Deleted Item Reference contains information about when a record was deleted and by whom. The display name consists of the entity’s display name and the record name.

In the view above, we won’t see records that were deleted by cascade relationships. Those records are restored when the record that triggered the cascade is restored. However, they can be retrieved using FetchXml, with data source pointing to bin.

There is a field called Total Records in the Deleted Item Reference entity, which stores the total number of records affected by a record deletion.

To restore data from the grid, select the records that you want to restore, click Restore, and then confirm the restore.

After this operation, the data should be available again for users. The deleted item reference record is removed and no longer available for the recovered record.

Query Recycle Bin data

Data that was deleted and had the recycle bin turned on can still be queried. To do so, when creating a FetchXML query or QueryExpression, you need to set DataSource to bin. Then use the query with RetrieveMultipleRequest.

FetchXml example:

<fetch top="50" datasource="bin">
  <entity name="odx_setting">
    <attribute name="odx_name" />
  </entity>
</fetch>

QueryExpression example:

public EntityCollection GetDeletedSettingRecords (IOrganizationService service)
{

    var query = new QueryExpression("odx_setting")
    {
        ColumnSet = new ColumnSet("name"),
        DataSource = "bin",
        TopCount = 50
    };

    return service.RetrieveMultiple(query);
}

Restore data with your code

In addition, if you are a developer, you have the ability to trigger a restore from both backend (C#) code or frontend. All you have to do is trigger a Restore action and pass as a parameter a reference to Deleted Record Reference or the restored record.

TypeScript example:

public async restoreRecord(deletedItemReferenceId: string) {
    let request = {
        Target: { "@odata.type": "Microsoft.Dynamics.CRM.deleteditemreference", deleteditemreferenceid: deletedItemReferenceId }, // mscrm.crmbaseentity

        getMetadata: () => {
            return {
                boundParameter: null,
                parameterTypes: {
                    Target: { typeName: "mscrm.crmbaseentity", structuralProperty: 5 }
                },
                operationType: 0, operationName: "Restore"
            };
        }
    };

    let responseBody = await Xrm.WebApi.online.execute(request);
    let result = await responseBody.json();
    let restoredRecordId = result["id"];
    return restoredRecordId;
}

C# example:

public static Guid? RestoreSettingRecord(ServiceClient client, Guid restoreId)
{     
    var restoreRequest = new RestoreRequest<odx_setting>()
    {
        Target = new odx_setting()
        {
            odx_name = "(Restore) Custom Setting",
            Id = restoreId
        }
    };

    var result = client.Execute(restoreRequest) as RestoreResponse;

    return result?.id;
}

Handling custom business logic

In some cases, we have custom logic that deletes related records using plugins or flows. In this case, the new feature won’t be able to restore those records correctly. When encountering such a problem, the documentation suggests writing your own plugin registered on the Restore message that will recover the missing data. 

Summary

As we can see, the Recycle Bin is a very useful feature. It is still in preview, so please keep in mind that the final functionality might slightly change when it is released.

I would also recommend to check out the new version of SQL 4 CDS V9.1 tool in XrmToolbox, which already uses this functionality.

Authors:

Daniel Pawłowski

Subscribe to oneDynamics

Sign up now to get access to the library of members-only issues.
Jamie Larson
Subscribe