This illustration shows how to submit a bulk delete job in Microsoft Dynamics CRM 2011 with BulkDeleteRequest. This example will be given in Jscript (SOAP) and in C# (.NET).
NOTES:
- You can schedule the job at regular intervals if desired using this request. See the following link for details.
http://msdn.microsoft.com/en-us/library/cc189846.aspx
- You can also define a start date and time for the job to occur.
- Lastly, this does not really act as a bulk delete request in the same sense as a bulk insert in SQL. It submits an asynchronous job to the server that runs in the background but deletes the records one by one. You will not really gain performance by this call versus a normal mass delete, but at least you won't have to babysit it.
Ok, here is what the code looks like!
BulkDeleteRequest req = new BulkDeleteRequest();
//send email to these receipients after job completes
req.ToRecipients = new Guid[] { new Guid("6E219F51-0310-4C4D-8C60-1C524E2BA7B3") };
//add cc recipients to the email here if desired
req.CCRecipients = new Guid[0];
req.JobName = "testbulkdeletejob";
req.SendEmailNotification = true;
req.RecurrencePattern = "";
//example of recurrence pattern
//int interval = 30;
//string pattern = String.Format(System.Globalization.CultureInfo.InvariantCulture, "FREQ=DAILY;INTERVAL={0};", interval);
//req.RecurrencePattern = pattern;
req.QuerySet = new QueryExpression[]
{
new QueryExpression()
{
EntityName = "account",
ColumnSet = new ColumnSet(true),
Criteria = new FilterExpression
{
FilterOperator = LogicalOperator.And,
Conditions =
{
new ConditionExpression
{
AttributeName = "name",
Operator = ConditionOperator.Equal,
Values = { "test account in code" }
}
}
}
}
};
BulkDeleteResponse resp = (BulkDeleteResponse)service.Execute(req);
If you need help instantiating a service object in .NET within a plugin check out this post:
http://mileyja.blogspot.com/2011/04/instantiating-service-object-within.html
if (typeof (SDK) == "undefined")
{ SDK = { __namespace: true }; }
//This will establish a more unique namespace for functions in this library. This will reduce the
// potential for functions to be overwritten due to a duplicate name when the library is loaded.
SDK.SAMPLES = {
_getServerUrl: function () {
///<summary>
/// Returns the URL for the SOAP endpoint using the context information available in the form
/// or HTML Web resource.
///</summary>
var ServicePath = "/XRMServices/2011/Organization.svc/web";
var serverUrl = "";
if (typeof GetGlobalContext == "function") {
var context = GetGlobalContext();
serverUrl = context.getServerUrl();
}
else {
if (typeof Xrm.Page.context == "object") {
serverUrl = Xrm.Page.context.getServerUrl();
}
else
{ throw new Error("Unable to access the server URL"); }
}
if (serverUrl.match(/\/$/)) {
serverUrl = serverUrl.substring(0, serverUrl.length - 1);
}
return serverUrl + ServicePath;
},
BulkDeleteRequest: function () {
var requestMain = ""
requestMain += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
requestMain += " <s:Body>";
requestMain += " <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
requestMain += " <request i:type=\"b:BulkDeleteRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">";
requestMain += " <a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <c:key>QuerySet</c:key>";
requestMain += " <c:value i:type=\"a:ArrayOfQueryExpression\">";
requestMain += " <a:QueryExpression>";
requestMain += " <a:ColumnSet>";
requestMain += " <a:AllColumns>true</a:AllColumns>";
requestMain += " <a:Columns xmlns:d=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\" />";
requestMain += " </a:ColumnSet>";
requestMain += " <a:Criteria>";
requestMain += " <a:Conditions>";
requestMain += " <a:ConditionExpression>";
requestMain += " <a:AttributeName>name</a:AttributeName>";
requestMain += " <a:Operator>Equal</a:Operator>";
requestMain += " <a:Values xmlns:d=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">";
requestMain += " <d:anyType i:type=\"e:string\" xmlns:e=\"http://www.w3.org/2001/XMLSchema\">test account in code</d:anyType>";
requestMain += " </a:Values>";
requestMain += " </a:ConditionExpression>";
requestMain += " </a:Conditions>";
requestMain += " <a:FilterOperator>And</a:FilterOperator>";
requestMain += " <a:Filters />";
requestMain += " </a:Criteria>";
requestMain += " <a:Distinct>false</a:Distinct>";
requestMain += " <a:EntityName>account</a:EntityName>";
requestMain += " <a:LinkEntities />";
requestMain += " <a:Orders />";
requestMain += " <a:PageInfo>";
requestMain += " <a:Count>0</a:Count>";
requestMain += " <a:PageNumber>0</a:PageNumber>";
requestMain += " <a:PagingCookie i:nil=\"true\" />";
requestMain += " <a:ReturnTotalRecordCount>false</a:ReturnTotalRecordCount>";
requestMain += " </a:PageInfo>";
requestMain += " <a:NoLock>false</a:NoLock>";
requestMain += " </a:QueryExpression>";
requestMain += " </c:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <c:key>JobName</c:key>";
requestMain += " <c:value i:type=\"d:string\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">testbulkdeletejob</c:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <c:key>SendEmailNotification</c:key>";
requestMain += " <c:value i:type=\"d:boolean\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">true</c:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <c:key>ToRecipients</c:key>";
requestMain += " <c:value i:type=\"d:ArrayOfguid\" xmlns:d=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">";
requestMain += " <d:guid>6e219f51-0310-4c4d-8c60-1c524e2ba7b3</d:guid>";
requestMain += " </c:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <c:key>CCRecipients</c:key>";
requestMain += " <c:value i:type=\"d:ArrayOfguid\" xmlns:d=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\" />";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <c:key>RecurrencePattern</c:key>";
requestMain += " <c:value i:type=\"d:string\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\" />";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <c:key>StartDateTime</c:key>";
requestMain += " <c:value i:type=\"d:dateTime\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">0001-01-01T00:00:00</c:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " </a:Parameters>";
requestMain += " <a:RequestId i:nil=\"true\" />";
requestMain += " <a:RequestName>BulkDelete</a:RequestName>";
requestMain += " </request>";
requestMain += " </Execute>";
requestMain += " </s:Body>";
requestMain += "</s:Envelope>";
var req = new XMLHttpRequest();
req.open("POST", SDK.SAMPLES._getServerUrl(), true)
req.setRequestHeader("Accept", "application/xml, text/xml, */*");
req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
var successCallback = null;
var errorCallback = null;
req.onreadystatechange = function () { SDK.SAMPLES.BulkDeleteResponse(req, successCallback, errorCallback); };
req.send(requestMain);
},
BulkDeleteResponse: function (req, successCallback, errorCallback) {
///<summary>
/// Recieves the assign response
///</summary>
///<param name="req" Type="XMLHttpRequest">
/// The XMLHttpRequest response
///</param>
///<param name="successCallback" Type="Function">
/// The function to perform when an successfult response is returned.
/// For this message no data is returned so a success callback is not really necessary.
///</param>
///<param name="errorCallback" Type="Function">
/// The function to perform when an error is returned.
/// This function accepts a JScript error returned by the _getError function
///</param>
if (req.readyState == 4) {
if (req.status == 200) {
if (successCallback != null)
{ successCallback(); }
}
else {
errorCallback(SDK.SAMPLES._getError(req.responseXML));
}
}
},
_getError: function (faultXml) {
///<summary>
/// Parses the WCF fault returned in the event of an error.
///</summary>
///<param name="faultXml" Type="XML">
/// The responseXML property of the XMLHttpRequest response.
///</param>
var errorMessage = "Unknown Error (Unable to parse the fault)";
if (typeof faultXml == "object") {
try {
var bodyNode = faultXml.firstChild.firstChild;
//Retrieve the fault node
for (var i = 0; i < bodyNode.childNodes.length; i++) {
var node = bodyNode.childNodes[i];
//NOTE: This comparison does not handle the case where the XML namespace changes
if ("s:Fault" == node.nodeName) {
for (var j = 0; j < node.childNodes.length; j++) {
var faultStringNode = node.childNodes[j];
if ("faultstring" == faultStringNode.nodeName) {
errorMessage = faultStringNode.text;
break;
}
}
break;
}
}
}
catch (e) { };
}
return new Error(errorMessage);
},
__namespace: true
};
To understand how to parse the response please review my post on using the DOM parser.
Now you can call the SDK.SAMPLES.BulkDeleteRequest function from your form jscript handler.
Thats all there is to it!
-