CRM 2011 – Bulk Deletion Jobs with C#

Roshan Mehta, 12 May 2013

The ability to programmatically execute a Bulk Deletion Job in Microsoft Dynamics CRM 2011 can be useful for developers in a number of scenarios. I have found it to be particularly useful when building and testing data migration tools in a clean instance of CRM, whereby you can quickly and easily delete records from multiple entities before running a test migration (or re-migration). In this post, we will see how we can utilise the BulkDeleteRequest and understand why it is better than the Delete operation.

 CRM 2011 Bulk Deletion Jobs with C#

Firstly, why is it better than calling the Delete method? The Delete method requires two parameters – the logical name of the entity, and the GUID of the record to delete. This means that if I want to delete all records for a particular entity, I would first have to execute a RetrieveMultiple operation, and then loop through each record to delete them. The problem here is that the RetrieveMultiple method is limited to only return 5,000 records at a time, so you would need to use paging queries to get all of the data you need. This is not a nice solution in terms of performance.

The BulkDeleteRequest is a lot better in terms of performance as we can simply execute a request to delete records for multiple entities at one time. Let’s take a look at a sample application which creates a whole bunch of Accounts, Contacts, and Leads in CRM. Each time I run the application, I want to be able to delete all of the records before we migrate the data. Here is what the bulk deletion method looks like:

private static void DeleteAllRecords()
{
    Console.WriteLine("Deleting all records. Please wait...");

    BulkDeleteRequest request = new BulkDeleteRequest 
    {
        JobName = "Delete All",
        ToRecipients = new Guid[] { },
        CCRecipients = new Guid[] { },
        RecurrencePattern = string.Empty,
        QuerySet = new QueryExpression[]
        {
            new QueryExpression { EntityName = "account" },
            new QueryExpression { EntityName = "contact" },
            new QueryExpression { EntityName = "lead" }
        }
    };

    BulkDeleteResponse response = (BulkDeleteResponse)_sdk.Execute(request);
    Guid jobId = response.JobId;

    bool deleting = true

    while (deleting)
    {
        Console.WriteLine("still deleting");
        Thread.Sleep(10000);    // poll crm every 10 seconds 

       
QueryExpression query = new QueryExpression { EntityName = "bulkdeleteoperation" };
        query.Criteria.AddCondition("asyncoperationid", ConditionOperator.Equal, jobId);
        query.Criteria.AddCondition("statecode", ConditionOperator.Equal, 3);
        query.Criteria.AddCondition("statuscode", ConditionOperator.Equal, 30);

        EntityCollection results = _sdk.RetrieveMultiple(query);
        if (results.Entities.Count > 0)
        {
            Console.WriteLine("finished deleting");
            deleting = false;
        }
    }
}

There are a few important things to note. The ToRecipients, CCRecipients and RecurrencePattern are all compulsory properties that need to be set but you can provide empty values if you wish. The QuerySet property accepts an array of QueryExpressions which allows us to delete records for multiple entity types in a single request. My QueryExpressions are simple and do not include any filters as we want to delete all records for each entity.

The BulkDeleteResponse returns the GUID of the bulk deletion job which I can then use to continuously poll CRM in order to find out if the bulk deletion has finished. The reason we have to do this is because the bulk deletion job runs asynchronously, so doesn’t give us any indication of its status. The completion of the job is defined by a statecode of 3 (Completed) and a statuscode of 30 (Suceeded). Once the application knows that the deletion job is complete, it can then run Create operations for Accounts, Contacts, and Leads.