Sample: Retrieve multiple records using the OData endpoint with JavaScript

 

Applies To: Dynamics CRM 2013

This sample code is for Microsoft Dynamics CRM 2013 and Microsoft Dynamics CRM Online. Download the Microsoft Dynamics CRM SDK package. It can be found in the following location in the download package:

SDK/SampleCode/JS/RESTEndpoint/JavaScriptRESTRetrieveMultiple

If you just want to see how this sample works you can install (import) the JavaScriptRESTRetrieveMultiple_1_0_0_0_managed.zip managed solution included in the download files. If you install this managed solution and want to create the Web resources using the names below, your solution publisher customization prefix cannot be “sample” unless you uninstall (delete) the managed solution.

Requirements

You can view this sample in the configuration page for the solution after you install it.

Sample User Interface

This sample uses the following four Web resources:

  • sample_/JavaScriptRESTRetrieveMultiple.htm
    An HTML page that provides the user interface and functions to call the SDK.REST.retrieveMultipleRecords function to retrieve data. This page is set as the configuration page for the sample solution.

  • sample_/Scripts/json2.js
    The content of json2.js is not included. This file is a public domain library you can download here.

    This library provides a global JSON object that is not available in Internet Explorer 7.

  • sample_/Scripts/SDK.REST.js
    This JavaScript library provides the SDK.REST.retrieveMultipleRecords function as well as other functions for using the REST endpoint for web resources.

  • sample_/Styles/JavaScriptRESTRetrieveMultiple.css
    This Cascading Style Sheet file provides styles for sample_/JavaScriptRESTRetrieveMultiple.htm.

Note

The customization prefix ” sample_” is not used in code. These samples will work using the customization prefix from any publisher. However the relative path of the simulated Scripts and Styles folder must be included in the name of the Web resources.

Demonstrates

By default the number of records returned by the REST Endpoint is limited to 50 records. This sample shows how to retrieve multiple records without regard to this limitation.

This sample uses the following approach:

  1. The document.onreadystatechange event handler includes code to set various UI elements to global variables, set the retrieveAccounts function as the click event handler for the Retrieve Accounts button (btnRetrieveAccounts), and then call the click method for the btnRetrieveAccounts button.

  2. The retrieveAccounts function clears the accountGrid and retrieves the number of records to retrieve from the numberOfAccountsToRetrieve select control. This value is appended to the OData System query options to be passed to the SDK.REST.retrieveMultipleRecords options parameter.

  3. The SDK.REST.retrieveMultipleRecords method accepts the following parameters:

    • type: The Schema Name of the Entity type record to retrieve. In this example uses “Account” so that account records are retrieved..

    • options: A String that represents the OData System Query Options to control the data returned. In this example the account Name and Telephone1 attributes are set and a $top query option is set to a value above the 50 record limit that is the default.

    • successCallback: The function that will be passed through and be called for each page of records returned. This example uses the retrieveAccountsCallBack function.

    • errorCallback: The function that will be passed through and be called by a failed response. This example uses an anonymous function that displays the message of any error using the alert function.

    • OnComplete: The function that will be called when all the requested records have been returned. This example uses the accountsRetrieveComplete function.

  4. The SDK.REST.retrieveMultipleRecords function prepares an XMLHttpRequest to retrieve the requested account records and sends the request.

    • Within the request onreadystatechange event handler, the first 50 results are passed back to the retrieveAccountsCallBack function as the successCallback. This function generates HTML rows for each record and appends them to the accountsGrid table.

    • If the total number of records requested using the $top query option has not yet been retrieved, the __next object contains a URL to retrieve the next set of 50 records. The URL is manipulated to extract just the query options and then passed into the SDK.REST.retrieveMultipleRecords function. This self-referential function call repeats until the requested number of records is returned or there are no more records to return.

    • When the __next object is no longer returned with the results, the accountsRetrieveComplete function is executed as the OnComplete function. This function sets the total number of records returned and displays a success message.

  5. After the page loads with the default values you can request a different number of records using the Maximum Number of Accounts to Retrieve (numberOfAccountsToRetrieve) select control and send another request by using the Retrieve Accounts (btnRetrieveAccounts) button.

sample_/JavaScriptRESTRetrieveMultiple.htm


<html lang="en-us">
<head>
 <title>REST Endpoint Paging with JScript</title>
 <meta http-equiv="X-UA-Compatible" content="IE=8" />
 <script src="../ClientGlobalContext.js.aspx" type="text/javascript"></script>
 <script src="Scripts/SDK.REST.js" type="text/javascript"></script>
 <script src="Scripts/json2.js" type="text/javascript"></script>
 <link href="Styles/JavaScriptRESTRetrieveMultiple.css" rel="stylesheet" type="text/css" />
 <script type="text/javascript">
  var accountsGrid; //The tbody element of the accountsTable
  var numberOfAccountsToRetrieve; // The select control with options for the number of records to retrieve.
  var btnRetrieveAccounts; //The button to retrieve accounts
  var accountsRetrieved; //The span displaying the number of account records retrieved.
  var successMessage; // The message displayed when records are returned.
  var totalAccountCount = 0;
  document.onreadystatechange = function () {
   if (document.readyState == "complete") {
    btnRetrieveAccounts = document.getElementById("btnRetrieveAccounts");
    accountsGrid = document.getElementById("accountsGrid");
    numberOfAccountsToRetrieve = document.getElementById("numberOfAccountsToRetrieve");
    accountsRetrieved = document.getElementById("accountsRetrieved");
    successMessage = document.getElementById("successMessage");
    btnRetrieveAccounts.onclick = retrieveAccounts;
    btnRetrieveAccounts.click();
   }
  }
  function retrieveAccounts() {
   ///<summary>
   /// Retrieves accounts by passing a filter to the SDK.RestEndpointPaging.RetrieveRecords function
   ///</summary>
   clearaccountsGrid();
   var number = parseInt(numberOfAccountsToRetrieve.options[numberOfAccountsToRetrieve.selectedIndex].value, 10);
   var options = "$select=Name,Telephone1&amp;$top=" + number;
   //The retrieveAccountsCallBack function is passed through as the successCallBack.
   SDK.REST.retrieveMultipleRecords("Account", options, retrieveAccountsCallBack, function (error) { alert(error.message); }, accountsRetrieveComplete);
  }
  function retrieveAccountsCallBack(retrievedAccounts) {
   ///<summary>
   /// This function is passed through the request and is iterated for each page of data
   /// This function appends rows to the accountsGrid.
   ///</summary>
   totalAccountCount = totalAccountCount + retrievedAccounts.length;
   for (var i = 0; i < retrievedAccounts.length; i++) {
    var account = retrievedAccounts[i];
    var row = document.createElement("tr");
    var nameCell = document.createElement("td");
    setElementText(nameCell, account.Name);
    row.appendChild(nameCell);
    var mainPhoneCell = document.createElement("td");
    setElementText(mainPhoneCell, (account.Telephone1 == null) ? "" : account.Telephone1);
    mainPhoneCell.className = "rightColumn";
    row.appendChild(mainPhoneCell);
    accountsGrid.appendChild(row);
   }
  }
  function accountsRetrieveComplete() {
   ///<summary>
   /// This function is called after all the records have been returned to update the actual total number of records.
   ///</summary>
   accountsRetrieved.innerText = totalAccountCount;
   successMessage.style.display = "block";
  }
  function clearaccountsGrid() {
   ///<summary>
   /// This function initializes the totalAccountCount and  clears all the rows from the accountsGrid
   /// in preparation for adding a new set of rows.
   ///</summary>
   successMessage.style.display = "none";
   totalAccountCount = 0;
   for (var i = accountsGrid.rows.length - 1; i >= 0; i--) {
    accountsGrid.deleteRow(i);
   }
  }
  function setElementText(element, text) {
   ///<summary>
   /// This function mitigates the fact that IE uses innerText and other browsers use textContent.
   ///</summary>
   if (typeof (element.innerText) != "undefined")
   { element.innerText = text; }
   else
   { element.textContent = text; }
  }
 </script>
</head>
<body>
 <table id="tableHeadings" summary="This table provides the headings for the list of accounts displayed in a grid.">
  <thead>
   <tr>
    <th class="leftColumn">
     Account Name
    </th>
    <th class="rightColumn">
     Main Phone
    </th>
   </tr>
  </thead>
 </table>

 <div id="tableContainer">
  <table id="accountsTable" rules="groups" summary="This table displays the accounts retrieved.">
   <tbody id="accountsGrid" />
  </table>

 </div>
 <div id="controlsContainer">
  <div>
   <span>Maximum Number of Accounts to Retrieve:
    <select id="numberOfAccountsToRetrieve">
     <option value="100" selected="selected">100</option>
     <option value="300">300</option>
     <option value="600">600</option>
     <option value="900">900</option>
    </select>
    <button id="btnRetrieveAccounts">
     Retrieve Accounts</button>
   </span>
  </div>
  <div id="successMessage" style="display: none;">
   Total Number of Accounts Retrieved : <span id="accountsRetrieved"></span>
  </div>
 </div>
</body>
</html>

sample_/Scripts/SDK.REST.js


if (typeof (SDK) == "undefined")
{ SDK = { __namespace: true }; }
SDK.REST = {
 _context: function () {
  ///<summary>
  /// Private function to the context object.
  ///</summary>
  ///<returns>Context</returns>
  if (typeof GetGlobalContext != "undefined")
  { return GetGlobalContext(); }
  else {
   if (typeof Xrm != "undefined") {
    return Xrm.Page.context;
   }
   else
   { throw new Error("Context is not available."); }
  }
 },
 _getClientUrl: function () {
  ///<summary>
  /// Private function to return the server URL from the context
  ///</summary>
  ///<returns>String</returns>
  var clientUrl = this._context().getClientUrl()

  return clientUrl;
 },
 _ODataPath: function () {
  ///<summary>
  /// Private function to return the path to the REST endpoint.
  ///</summary>
  ///<returns>String</returns>
  return this._getClientUrl() + "/XRMServices/2011/OrganizationData.svc/";
 },
 _errorHandler: function (req) {
  ///<summary>
  /// Private function return an Error object to the errorCallback
  ///</summary>
  ///<param name="req" type="XMLHttpRequest">
  /// The XMLHttpRequest response that returned an error.
  ///</param>
  ///<returns>Error</returns>
  //Error descriptions come from https://support.microsoft.com/kb/193625
  if (req.status == 12029)
  { return new Error("The attempt to connect to the server failed."); }
  if (req.status == 12007)
  { return new Error("The server name could not be resolved."); }
  var errorText;
  try
        { errorText = JSON.parse(req.responseText).error.message.value; }
  catch (e)
        { errorText = req.responseText }

  return new Error("Error : " +
        req.status + ": " +
        req.statusText + ": " + errorText);
 },
 _dateReviver: function (key, value) {
  ///<summary>
  /// Private function to convert matching string values to Date objects.
  ///</summary>
  ///<param name="key" type="String">
  /// The key used to identify the object property
  ///</param>
  ///<param name="value" type="String">
  /// The string value representing a date
  ///</param>
  var a;
  if (typeof value === 'string') {
   a = /Date\(([-+]?\d+)\)/.exec(value);
   if (a) {
    return new Date(parseInt(value.replace("/Date(", "").replace(")/", ""), 10));
   }
  }
  return value;
 },
 _parameterCheck: function (parameter, message) {
  ///<summary>
  /// Private function used to check whether required parameters are null or undefined
  ///</summary>
  ///<param name="parameter" type="Object">
  /// The parameter to check;
  ///</param>
  ///<param name="message" type="String">
  /// The error message text to include when the error is thrown.
  ///</param>
  if ((typeof parameter === "undefined") || parameter === null) {
   throw new Error(message);
  }
 },
 _stringParameterCheck: function (parameter, message) {
  ///<summary>
  /// Private function used to check whether required parameters are null or undefined
  ///</summary>
  ///<param name="parameter" type="String">
  /// The string parameter to check;
  ///</param>
  ///<param name="message" type="String">
  /// The error message text to include when the error is thrown.
  ///</param>
  if (typeof parameter != "string") {
   throw new Error(message);
  }
 },
 _callbackParameterCheck: function (callbackParameter, message) {
  ///<summary>
  /// Private function used to check whether required callback parameters are functions
  ///</summary>
  ///<param name="callbackParameter" type="Function">
  /// The callback parameter to check;
  ///</param>
  ///<param name="message" type="String">
  /// The error message text to include when the error is thrown.
  ///</param>
  if (typeof callbackParameter != "function") {
   throw new Error(message);
  }
 },
 createRecord: function (object, type, successCallback, errorCallback) {
  ///<summary>
  /// Sends an asynchronous request to create a new record.
  ///</summary>
  ///<param name="object" type="Object">
  /// A JavaScript object with properties corresponding to the Schema name of
  /// entity attributes that are valid for create operations.
  ///</param>
  ///<param name="type" type="String">
  /// The Schema Name of the Entity type record to create.
  /// For an Account record, use "Account"
  ///</param>
  ///<param name="successCallback" type="Function">
  /// The function that will be passed through and be called by a successful response. 
  /// This function can accept the returned record as a parameter.
  /// </param>
  ///<param name="errorCallback" type="Function">
  /// The function that will be passed through and be called by a failed response. 
  /// This function must accept an Error object as a parameter.
  /// </param>
  this._parameterCheck(object, "SDK.REST.createRecord requires the object parameter.");
  this._stringParameterCheck(type, "SDK.REST.createRecord requires the type parameter is a string.");
  this._callbackParameterCheck(successCallback, "SDK.REST.createRecord requires the successCallback is a function.");
  this._callbackParameterCheck(errorCallback, "SDK.REST.createRecord requires the errorCallback is a function.");
  var req = new XMLHttpRequest();
  req.open("POST", encodeURI(this._ODataPath() + type + "Set"), true);
  req.setRequestHeader("Accept", "application/json");
  req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
  req.onreadystatechange = function () {
   if (this.readyState == 4 /* complete */) {
    req.onreadystatechange = null;
    if (this.status == 201) {
     successCallback(JSON.parse(this.responseText, SDK.REST._dateReviver).d);
    }
    else {
     errorCallback(SDK.REST._errorHandler(this));
    }
   }
  };
  req.send(JSON.stringify(object));
 },
 retrieveRecord: function (id, type, select, expand, successCallback, errorCallback) {
  ///<summary>
  /// Sends an asynchronous request to retrieve a record.
  ///</summary>
  ///<param name="id" type="String">
  /// A String representing the GUID value for the record to retrieve.
  ///</param>
  ///<param name="type" type="String">
  /// The Schema Name of the Entity type record to retrieve.
  /// For an Account record, use "Account"
  ///</param>
  ///<param name="select" type="String">
  /// A String representing the $select OData System Query Option to control which
  /// attributes will be returned. This is a comma separated list of Attribute names that are valid for retrieve.
  /// If null all properties for the record will be returned
  ///</param>
  ///<param name="expand" type="String">
  /// A String representing the $expand OData System Query Option value to control which
  /// related records are also returned. This is a comma separated list of of up to 6 entity relationship names
  /// If null no expanded related records will be returned.
  ///</param>
  ///<param name="successCallback" type="Function">
  /// The function that will be passed through and be called by a successful response. 
  /// This function must accept the returned record as a parameter.
  /// </param>
  ///<param name="errorCallback" type="Function">
  /// The function that will be passed through and be called by a failed response. 
  /// This function must accept an Error object as a parameter.
  /// </param>
  this._stringParameterCheck(id, "SDK.REST.retrieveRecord requires the id parameter is a string.");
  this._stringParameterCheck(type, "SDK.REST.retrieveRecord requires the type parameter is a string.");
  if (select != null)
   this._stringParameterCheck(select, "SDK.REST.retrieveRecord requires the select parameter is a string.");
  if (expand != null)
   this._stringParameterCheck(expand, "SDK.REST.retrieveRecord requires the expand parameter is a string.");
  this._callbackParameterCheck(successCallback, "SDK.REST.retrieveRecord requires the successCallback parameter is a function.");
  this._callbackParameterCheck(errorCallback, "SDK.REST.retrieveRecord requires the errorCallback parameter is a function.");

  var systemQueryOptions = "";

  if (select != null || expand != null) {
   systemQueryOptions = "?";
   if (select != null) {
    var selectString = "$select=" + select;
    if (expand != null) {
     selectString = selectString + "," + expand;
    }
    systemQueryOptions = systemQueryOptions + selectString;
   }
   if (expand != null) {
    systemQueryOptions = systemQueryOptions + "&amp;$expand=" + expand;
   }
  }


  var req = new XMLHttpRequest();
  req.open("GET", encodeURI(this._ODataPath() + type + "Set(guid'" + id + "')" + systemQueryOptions), true);
  req.setRequestHeader("Accept", "application/json");
  req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
  req.onreadystatechange = function () {
   if (this.readyState == 4 /* complete */) {
    req.onreadystatechange = null;
    if (this.status == 200) {
     successCallback(JSON.parse(this.responseText, SDK.REST._dateReviver).d);
    }
    else {
     errorCallback(SDK.REST._errorHandler(this));
    }
   }
  };
  req.send();
 },
 updateRecord: function (id, object, type, successCallback, errorCallback) {
  ///<summary>
  /// Sends an asynchronous request to update a record.
  ///</summary>
  ///<param name="id" type="String">
  /// A String representing the GUID value for the record to retrieve.
  ///</param>
  ///<param name="object" type="Object">
  /// A JavaScript object with properties corresponding to the Schema Names for
  /// entity attributes that are valid for update operations.
  ///</param>
  ///<param name="type" type="String">
  /// The Schema Name of the Entity type record to retrieve.
  /// For an Account record, use "Account"
  ///</param>
  ///<param name="successCallback" type="Function">
  /// The function that will be passed through and be called by a successful response. 
  /// Nothing will be returned to this function.
  /// </param>
  ///<param name="errorCallback" type="Function">
  /// The function that will be passed through and be called by a failed response. 
  /// This function must accept an Error object as a parameter.
  /// </param>
  this._stringParameterCheck(id, "SDK.REST.updateRecord requires the id parameter.");
  this._parameterCheck(object, "SDK.REST.updateRecord requires the object parameter.");
  this._stringParameterCheck(type, "SDK.REST.updateRecord requires the type parameter.");
  this._callbackParameterCheck(successCallback, "SDK.REST.updateRecord requires the successCallback is a function.");
  this._callbackParameterCheck(errorCallback, "SDK.REST.updateRecord requires the errorCallback is a function.");
  var req = new XMLHttpRequest();

  req.open("POST", encodeURI(this._ODataPath() + type + "Set(guid'" + id + "')"), true);
  req.setRequestHeader("Accept", "application/json");
  req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
  req.setRequestHeader("X-HTTP-Method", "MERGE");
  req.onreadystatechange = function () {
   if (this.readyState == 4 /* complete */) {
    req.onreadystatechange = null;
    if (this.status == 204 || this.status == 1223) {
     successCallback();
    }
    else {
     errorCallback(SDK.REST._errorHandler(this));
    }
   }
  };
  req.send(JSON.stringify(object));
 },
 deleteRecord: function (id, type, successCallback, errorCallback) {
  ///<summary>
  /// Sends an asynchronous request to delete a record.
  ///</summary>
  ///<param name="id" type="String">
  /// A String representing the GUID value for the record to delete.
  ///</param>
  ///<param name="type" type="String">
  /// The Schema Name of the Entity type record to delete.
  /// For an Account record, use "Account"
  ///</param>
  ///<param name="successCallback" type="Function">
  /// The function that will be passed through and be called by a successful response. 
  /// Nothing will be returned to this function.
  /// </param>
  ///<param name="errorCallback" type="Function">
  /// The function that will be passed through and be called by a failed response. 
  /// This function must accept an Error object as a parameter.
  /// </param>
  this._stringParameterCheck(id, "SDK.REST.deleteRecord requires the id parameter.");
  this._stringParameterCheck(type, "SDK.REST.deleteRecord requires the type parameter.");
  this._callbackParameterCheck(successCallback, "SDK.REST.deleteRecord requires the successCallback is a function.");
  this._callbackParameterCheck(errorCallback, "SDK.REST.deleteRecord requires the errorCallback is a function.");
  var req = new XMLHttpRequest();
  req.open("POST", encodeURI(this._ODataPath() + type + "Set(guid'" + id + "')"), true);
  req.setRequestHeader("Accept", "application/json");
  req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
  req.setRequestHeader("X-HTTP-Method", "DELETE");
  req.onreadystatechange = function () {

   if (this.readyState == 4 /* complete */) {
    req.onreadystatechange = null;
    if (this.status == 204 || this.status == 1223) {
     successCallback();
    }
    else {
     errorCallback(SDK.REST._errorHandler(this));
    }
   }
  };
  req.send();

 },
 retrieveMultipleRecords: function (type, options, successCallback, errorCallback, OnComplete) {
  ///<summary>
  /// Sends an asynchronous request to retrieve records.
  ///</summary>
  ///<param name="type" type="String">
  /// The Schema Name of the Entity type record to retrieve.
  /// For an Account record, use "Account"
  ///</param>
  ///<param name="options" type="String">
  /// A String representing the OData System Query Options to control the data returned
  ///</param>
  ///<param name="successCallback" type="Function">
  /// The function that will be passed through and be called for each page of records returned.
  /// Each page is 50 records. If you expect that more than one page of records will be returned,
  /// this function should loop through the results and push the records into an array outside of the function.
  /// Use the OnComplete event handler to know when all the records have been processed.
  /// </param>
  ///<param name="errorCallback" type="Function">
  /// The function that will be passed through and be called by a failed response. 
  /// This function must accept an Error object as a parameter.
  /// </param>
  ///<param name="OnComplete" type="Function">
  /// The function that will be called when all the requested records have been returned.
  /// No parameters are passed to this function.
  /// </param>
  this._stringParameterCheck(type, "SDK.REST.retrieveMultipleRecords requires the type parameter is a string.");
  if (options != null)
   this._stringParameterCheck(options, "SDK.REST.retrieveMultipleRecords requires the options parameter is a string.");
  this._callbackParameterCheck(successCallback, "SDK.REST.retrieveMultipleRecords requires the successCallback parameter is a function.");
  this._callbackParameterCheck(errorCallback, "SDK.REST.retrieveMultipleRecords requires the errorCallback parameter is a function.");
  this._callbackParameterCheck(OnComplete, "SDK.REST.retrieveMultipleRecords requires the OnComplete parameter is a function.");

  var optionsString;
  if (options != null) {
   if (options.charAt(0) != "?") {
    optionsString = "?" + options;
   }
   else
   { optionsString = options; }
  }
  var req = new XMLHttpRequest();
  req.open("GET", this._ODataPath() + type + "Set" + optionsString, true);
  req.setRequestHeader("Accept", "application/json");
  req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
  req.onreadystatechange = function () {
   if (this.readyState == 4 /* complete */) {
    req.onreadystatechange = null;
    if (this.status == 200) {
     var returned = JSON.parse(this.responseText, SDK.REST._dateReviver).d;
     successCallback(returned.results);
     if (returned.__next != null) {
      var queryOptions = returned.__next.substring((SDK.REST._ODataPath() + type + "Set").length);
      SDK.REST.retrieveMultipleRecords(type, queryOptions, successCallback, errorCallback, OnComplete);
     }
     else
     { OnComplete(); }
    }
    else {
     errorCallback(SDK.REST._errorHandler(this));
    }
   }
  };
  req.send();
 },
 associateRecords: function (parentId, parentType, relationshipName, childId, childType, successCallback, errorCallback) {
  this._stringParameterCheck(parentId, "SDK.REST.associateRecords requires the parentId parameter is a string.");
  ///<param name="parentId" type="String">
  /// The Id of the record to be the parent record in the relationship
  /// </param>
  ///<param name="parentType" type="String">
  /// The Schema Name of the Entity type for the parent record.
  /// For an Account record, use "Account"
  /// </param>
  ///<param name="relationshipName" type="String">
  /// The Schema Name of the Entity Relationship to use to associate the records.
  /// To associate account records as a Parent account, use "Referencedaccount_parent_account"
  /// </param>
  ///<param name="childId" type="String">
  /// The Id of the record to be the child record in the relationship
  /// </param>
  ///<param name="childType" type="String">
  /// The Schema Name of the Entity type for the child record.
  /// For an Account record, use "Account"
  /// </param>
  ///<param name="successCallback" type="Function">
  /// The function that will be passed through and be called by a successful response. 
  /// Nothing will be returned to this function.
  /// </param>
  ///<param name="errorCallback" type="Function">
  /// The function that will be passed through and be called by a failed response. 
  /// This function must accept an Error object as a parameter.
  /// </param>
  this._stringParameterCheck(parentType, "SDK.REST.associateRecords requires the parentType parameter is a string.");
  this._stringParameterCheck(relationshipName, "SDK.REST.associateRecords requires the relationshipName parameter is a string.");
  this._stringParameterCheck(childId, "SDK.REST.associateRecords requires the childId parameter is a string.");
  this._stringParameterCheck(childType, "SDK.REST.associateRecords requires the childType parameter is a string.");
  this._callbackParameterCheck(successCallback, "SDK.REST.associateRecords requires the successCallback parameter is a function.");
  this._callbackParameterCheck(errorCallback, "SDK.REST.associateRecords requires the errorCallback parameter is a function.");

  var req = new XMLHttpRequest();
  req.open("POST", encodeURI(this._ODataPath() + parentType + "Set(guid'" + parentId + "')/$links/" + relationshipName), true);
  req.setRequestHeader("Accept", "application/json");
  req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
  req.onreadystatechange = function () {
   if (this.readyState == 4 /* complete */) {
    req.onreadystatechange = null;
    if (this.status == 204 || this.status == 1223) {
     successCallback();
    }
    else {
     errorCallback(SDK.REST._errorHandler(this));
    }
   }
  };
  var childEntityReference = {}
  childEntityReference.uri = this._ODataPath() + "/" + childType + "Set(guid'" + childId + "')";
  req.send(JSON.stringify(childEntityReference));
 },
 disassociateRecords: function (parentId, parentType, relationshipName, childId, successCallback, errorCallback) {
  this._stringParameterCheck(parentId, "SDK.REST.disassociateRecords requires the parentId parameter is a string.");
  ///<param name="parentId" type="String">
  /// The Id of the record to be the parent record in the relationship
  /// </param>
  ///<param name="parentType" type="String">
  /// The Schema Name of the Entity type for the parent record.
  /// For an Account record, use "Account"
  /// </param>
  ///<param name="relationshipName" type="String">
  /// The Schema Name of the Entity Relationship to use to disassociate the records.
  /// To disassociate account records as a Parent account, use "Referencedaccount_parent_account"
  /// </param>
  ///<param name="childId" type="String">
  /// The Id of the record to be disassociated as the child record in the relationship
  /// </param>
  ///<param name="successCallback" type="Function">
  /// The function that will be passed through and be called by a successful response. 
  /// Nothing will be returned to this function.
  /// </param>
  ///<param name="errorCallback" type="Function">
  /// The function that will be passed through and be called by a failed response. 
  /// This function must accept an Error object as a parameter.
  /// </param>
  this._stringParameterCheck(parentType, "SDK.REST.disassociateRecords requires the parentType parameter is a string.");
  this._stringParameterCheck(relationshipName, "SDK.REST.disassociateRecords requires the relationshipName parameter is a string.");
  this._stringParameterCheck(childId, "SDK.REST.disassociateRecords requires the childId parameter is a string.");
  this._callbackParameterCheck(successCallback, "SDK.REST.disassociateRecords requires the successCallback parameter is a function.");
  this._callbackParameterCheck(errorCallback, "SDK.REST.disassociateRecords requires the errorCallback parameter is a function.");

  var req = new XMLHttpRequest();
  req.open("POST", encodeURI(this._ODataPath() + parentType + "Set(guid'" + parentId + "')/$links/" + relationshipName + "(guid'" + childId + "')"), true);
  req.setRequestHeader("Accept", "application/json");
  req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
  req.setRequestHeader("X-HTTP-Method", "DELETE");
  req.onreadystatechange = function () {
   if (this.readyState == 4 /* complete */) {
    req.onreadystatechange = null;
    if (this.status == 204 || this.status == 1223) {
     successCallback();
    }
    else {
     errorCallback(SDK.REST._errorHandler(this));
    }
   }
  };
  req.send();
 },
 __namespace: true
};

sample_/Styles/JavaScriptRESTRetrieveMultiple.css

See Also

Query Microsoft Dynamics CRM 2013 data using the OData endpoint
Limitations on number of records returned
Use the OData endpoint with Ajax and JScript web resources
Sample: Associate and disassociate records using the OData endpoint with JavaScript
Use the OData endpoint with web resources
Technical Article: Using Option Set Options with the REST Endpoint - JScript