MS CRM 2011 RetrieveMultiple with JScript JQuery Silverlight LINQ FetchXML and QueryExpression
原创地址:http://www.cnblogs.com/jfzhu/archive/2013/03/07/2947306.html
转载请注明出处
(一) JScript
JScript一次最多返回50条数据,想要获得更多数据,需要使用__next 对象
1. 同步操作返回少于50条数据
<html xmlns="http://www.w3.org/1999/xhtml" > <head> <script src="ClientGlobalContext.js.aspx" type="text/javascript"></script> <script src="aw_json.js" type="text/javascript"></script> <script src="new_TestLibrary.js" type="text/javascript"></script> <script type="text/javascript"> function clearaccountsGrid() { var accountsGrid = document.getElementById("accountsGrid"); 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; } } function Button1_onclick() { clearaccountsGrid(); RetrieveAllAccounts() } function RetrieveAllAccounts() { try { var oDataPath = TestLibrary._ODataPath(); var filter = "/AccountSet?$select=Name"; var retrieveRecordsReq = new XMLHttpRequest(); retrieveRecordsReq.open("GET", oDataPath + filter, false); retrieveRecordsReq.setRequestHeader("Accept", "application/json"); retrieveRecordsReq.setRequestHeader("Content-Type", "application/json; charset=utf-8"); retrieveRecordsReq.send(); var retrievedResponse = JSON.parse(retrieveRecordsReq.responseText).d; var totalAccountCount = retrievedResponse.results.length; setElementText(document.getElementById("totalLabel"), "There are " + totalAccountCount + " accounts"); if (retrievedResponse.results.length > 0) { var accountsGrid = document.getElementById("accountsGrid"); for (var i = 0; i < retrievedResponse.results.length; i++) { var account = retrievedResponse.results[i]; var row = document.createElement("tr"); var nameCell = document.createElement("td"); setElementText(nameCell, account.Name); row.appendChild(nameCell); accountsGrid.appendChild(row); } } } catch (e) { alert(e.Message); } } </script> <title></title> </head> <body> <label id="totalLabel"></label> <input id="Button1" type="button" value="button" onclick="return Button1_onclick()" /> <div id="tableContainer"> <table id="accountsTable" rules="groups" summary="This table displays the accounts retrieved."> <tbody id="accountsGrid" /> </table> </div> </body> </html>
if (typeof (TestLibrary) == "undefined") { TestLibrary = { __namespace: true }; } TestLibrary = { Name: "TestLibrary", _context: function () { if (typeof GetGlobalContext != "undefined") { return GetGlobalContext(); } else { if (typeof Xrm != "undefined") { return Xrm.Page.context; } else { throw new Error("Context is not available."); } } }, _getServerUrl: function () { var serverUrl = TestLibrary._context().getServerUrl() if (serverUrl.match(/\/$/)) { serverUrl = serverUrl.substring(0, serverUrl.length - 1); } return serverUrl; }, _ODataPath: function () { return TestLibrary._getServerUrl() + "/XRMServices/2011/OrganizationData.svc/"; } }
2. 同步操作返回大于50条数据
<html xmlns="http://www.w3.org/1999/xhtml" > <head> <script src="ClientGlobalContext.js.aspx" type="text/javascript"></script> <script src="aw_json.js" type="text/javascript"></script> <script src="new_TestLibrary.js" type="text/javascript"></script> <script type="text/javascript"> function clearaccountsGrid() { var accountsGrid = document.getElementById("accountsGrid"); 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; } } function Button1_onclick() { clearaccountsGrid(); RetrieveAllAccounts() } function RetrieveAllAccounts() { try { var oDataPath = TestLibrary._ODataPath(); var type = "AccountSet"; var filter = "?$select=Name"; var retrieveRecordsReq = new XMLHttpRequest(); retrieveRecordsReq.open("GET", oDataPath + type + filter, false); var totalAccountCount = 0; retrieveRecordsReq.setRequestHeader("Accept", "application/json"); retrieveRecordsReq.setRequestHeader("Content-Type", "application/json; charset=utf-8"); retrieveRecordsReq.send(); var retrievedResponse = JSON.parse(retrieveRecordsReq.responseText).d; totalAccountCount = totalAccountCount + retrievedResponse.results.length; setElementText(document.getElementById("totalLabel"), "There are " + totalAccountCount + " accounts"); if (retrievedResponse.results.length > 0) { var accountsGrid = document.getElementById("accountsGrid"); for (var i = 0; i < retrievedResponse.results.length; i++) { var account = retrievedResponse.results[i]; var row = document.createElement("tr"); var nameCell = document.createElement("td"); setElementText(nameCell, account.Name); row.appendChild(nameCell); accountsGrid.appendChild(row); } } while (retrievedResponse.__next != null) { var queryOptions = retrievedResponse.__next.substring((TestLibrary._ODataPath() + "AccountSet").length); retrieveRecordsReq = new XMLHttpRequest(); retrieveRecordsReq.open("GET", oDataPath + type + queryOptions, false); retrieveRecordsReq.setRequestHeader("Accept", "application/json"); retrieveRecordsReq.setRequestHeader("Content-Type", "application/json; charset=utf-8"); retrieveRecordsReq.send(); retrievedResponse = JSON.parse(retrieveRecordsReq.responseText).d; totalAccountCount = totalAccountCount + retrievedResponse.results.length; setElementText(document.getElementById("totalLabel"), "There are " + totalAccountCount + " accounts"); if (retrievedResponse.results.length > 0) { var accountsGrid = document.getElementById("accountsGrid"); for (var i = 0; i < retrievedResponse.results.length; i++) { var account = retrievedResponse.results[i]; var row = document.createElement("tr"); var nameCell = document.createElement("td"); setElementText(nameCell, account.Name); row.appendChild(nameCell); accountsGrid.appendChild(row); } } } } catch (e) { alert(e.Message); } } </script> <title></title> </head> <body> <label id="totalLabel"></label> <input id="Button1" type="button" value="button" onclick="return Button1_onclick()" /> <div id="tableContainer"> <table id="accountsTable" rules="groups" summary="This table displays the accounts retrieved."> <tbody id="accountsGrid" /> </table> </div> </body> </html>
3. 异步操作返回少于50条数据
<html xmlns="http://www.w3.org/1999/xhtml" > <head> <script src="ClientGlobalContext.js.aspx" type="text/javascript"></script> <script src="aw_json.js" type="text/javascript"></script> <script src="new_TestLibrary.js" type="text/javascript"></script> <script type="text/javascript"> var totalAccountCount = 0; function retrieveAccounts() { clearaccountsGrid(); var req = new XMLHttpRequest(); req.open("GET", TestLibrary._ODataPath() + "AccountSet?$select=Name", true); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.onreadystatechange = function () { if (this.readyState == 4 /* complete */) { if (this.status == 200) { var returned = JSON.parse(this.responseText).d; retrieveAccountsCallBack(returned.results); } else { alert(_errorHandler(this).message); } } }; req.send(); } function _errorHandler(req) { 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); } function retrieveAccountsCallBack(retrievedAccounts) { totalAccountCount = totalAccountCount + retrievedAccounts.length; setElementText(document.getElementById("totalLabel"), "There are " + totalAccountCount + " accounts"); var accountsGrid = document.getElementById("accountsGrid"); 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); accountsGrid.appendChild(row); } } function clearaccountsGrid() { totalAccountCount = 0; var accountsGrid = document.getElementById("accountsGrid"); 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; } } function Button1_onclick() { retrieveAccounts() } </script> <title></title> </head> <body> <label id="totalLabel"></label> <input id="Button1" type="button" value="button" onclick="return Button1_onclick()" /> <div id="tableContainer"> <table id="accountsTable" rules="groups" summary="This table displays the accounts retrieved."> <tbody id="accountsGrid" /> </table> </div> </body> </html>
4. 异步操作返回大于50条数据
<html xmlns="http://www.w3.org/1999/xhtml" > <head> <script src="ClientGlobalContext.js.aspx" type="text/javascript"></script> <script src="aw_json.js" type="text/javascript"></script> <script src="new_TestLibrary.js" type="text/javascript"></script> <script type="text/javascript"> var totalAccountCount = 0; function retrieveAccounts() { clearaccountsGrid(); var options = "$select=Name"; //The retrieveAccountsCallBack function is passed through as the successCallBack. TestLibrary.RetrieveMultipleRecords("Account", options, retrieveAccountsCallBack, function (error) { alert(error.message); }, function () { alert("complete")}); } function retrieveAccountsCallBack(retrievedAccounts) { totalAccountCount = totalAccountCount + retrievedAccounts.length; setElementText(document.getElementById("totalLabel"), "There are " + totalAccountCount + " accounts"); var accountsGrid = document.getElementById("accountsGrid"); 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); accountsGrid.appendChild(row); } } function clearaccountsGrid() { totalAccountCount = 0; var accountsGrid = document.getElementById("accountsGrid"); 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; } } function Button1_onclick() { retrieveAccounts() } </script> <title></title> </head> <body> <label id="totalLabel"></label> <input id="Button1" type="button" value="button" onclick="return Button1_onclick()" /> <div id="tableContainer"> <table id="accountsTable" rules="groups" summary="This table displays the accounts retrieved."> <tbody id="accountsGrid" /> </table> </div> </body> </html>
TestLibrary.js是SDK.REST.js 的精简版,你完全可以也使用SDK.REST.js
if (typeof (TestLibrary) == "undefined") { TestLibrary = { __namespace: true }; } TestLibrary = { Name: "TestLibrary", _context: function () { if (typeof GetGlobalContext != "undefined") { return GetGlobalContext(); } else { if (typeof Xrm != "undefined") { return Xrm.Page.context; } else { throw new Error("Context is not available."); } } }, _getServerUrl: function () { var serverUrl = TestLibrary._context().getServerUrl() if (serverUrl.match(/\/$/)) { serverUrl = serverUrl.substring(0, serverUrl.length - 1); } return serverUrl; }, _ODataPath: function () { return TestLibrary._getServerUrl() + "/XRMServices/2011/OrganizationData.svc/"; }, RetrieveMultipleRecords: function (type, options, successCallback, errorCallback, OnComplete) { var optionsString; if (options != null) { if (options.charAt(0) != "?") { optionsString = "?" + options; } else { optionsString = options; } } var req = new XMLHttpRequest(); req.open("GET", TestLibrary._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 */) { if (this.status == 200) { var returned = JSON.parse(this.responseText).d; successCallback(returned.results); if (returned.__next != null) { var queryOptions = returned.__next.substring((TestLibrary._ODataPath() + type + "Set").length); TestLibrary.RetrieveMultipleRecords(type, queryOptions, successCallback, errorCallback, OnComplete); } else { OnComplete(); } } else { errorCallback(TestLibrary._errorHandler(this)); } } }; req.send(); }, _errorHandler: function (req) { 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); } }
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."); } } }, _getServerUrl: function () { ///<summary> /// Private function to return the server URL from the context ///</summary> ///<returns>String</returns> var serverUrl = this._context().getServerUrl() if (serverUrl.match(/\/$/)) { serverUrl = serverUrl.substring(0, serverUrl.length - 1); } return serverUrl; }, _ODataPath: function () { ///<summary> /// Private function to return the path to the REST endpoint. ///</summary> ///<returns>String</returns> return this._getServerUrl() + "/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 http://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 */) { 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 + "&$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 */) { 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 */) { 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 */) { 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 */) { 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 */) { 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 */) { if (this.status == 204 || this.status == 1223) { successCallback(); } else { errorCallback(SDK.REST._errorHandler(this)); } } }; req.send(); }, __namespace: true };
(二) JQuery
JQuery使用AJAX,所以全部都是异步操作。在下面的例子中直接使用SDK.JQuery.js
<html xmlns="http://www.w3.org/1999/xhtml" > <head> <script src="ClientGlobalContext.js.aspx" type="text/javascript"></script> <script src="aw_json.js" type="text/javascript"></script> <script src="new_jquery.js" type="text/javascript"></script> <script src="new_sdk.jquery.js" type="text/javascript"></script> <script type="text/javascript"> var totalAccountCount = 0; function retrieveAccounts() { clearaccountsGrid(); SDK.JQuery.retrieveMultipleRecords( "Account", "$select=Name", retrieveAccountsCallBack, function (error) { alert(error.message); }, function () { alert("complete"); } ); } function retrieveAccountsCallBack(retrievedAccounts) { totalAccountCount = totalAccountCount + retrievedAccounts.length; setElementText(document.getElementById("totalLabel"), "There are " + totalAccountCount + " accounts"); var accountsGrid = document.getElementById("accountsGrid"); 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); accountsGrid.appendChild(row); } } function clearaccountsGrid() { totalAccountCount = 0; var accountsGrid = document.getElementById("accountsGrid"); 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; } } function Button1_onclick() { retrieveAccounts() } </script> <title></title> </head> <body> <label id="totalLabel"></label> <input id="Button1" type="button" value="button" onclick="return Button1_onclick()" /> <div id="tableContainer"> <table id="accountsTable" rules="groups" summary="This table displays the accounts retrieved."> <tbody id="accountsGrid" /> </table> </div> </body> </html>
SDK.JQuery.js
/// <reference path="jquery1.4.1vsdoc.js" /> if (typeof (SDK) == "undefined") { SDK = { __namespace: true }; } SDK.JQuery = { _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."); } } }, _getServerUrl: function () { ///<summary> /// Private function to return the server URL from the context ///</summary> ///<returns>String</returns> var serverUrl = this._context().getServerUrl() if (serverUrl.match(/\/$/)) { serverUrl = serverUrl.substring(0, serverUrl.length - 1); } return serverUrl; }, _ODataPath: function () { ///<summary> /// Private function to return the path to the REST endpoint. ///</summary> ///<returns>String</returns> return this._getServerUrl() + "/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> return new Error("Error : " + req.status + ": " + req.statusText + ": " + JSON.parse(req.responseText).error.message.value); }, _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> this._parameterCheck(object, "SDK.JQuery.createRecord requires the object parameter."); ///<param name="type" type="String"> /// The Schema Name of the Entity type record to create. /// For an Account record, use "Account" ///</param> this._stringParameterCheck(type, "SDK.JQuery.createRecord requires the type parameter is a string."); ///<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> this._callbackParameterCheck(successCallback, "SDK.JQuery.createRecord requires the successCallback is a function."); ///<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._callbackParameterCheck(errorCallback, "SDK.JQuery.createRecord requires the errorCallback is a function."); var jsonEntity = window.JSON.stringify(object); $.ajax({ type: "POST", contentType: "application/json; charset=utf-8", datatype: "json", url: this._ODataPath() + type + "Set", data: jsonEntity, beforeSend: function (xhr) { //Specifying this header ensures that the results will be returned as JSON. xhr.setRequestHeader("Accept", "application/json"); }, success: function (data, textStatus, xhr) { successCallback(data.d); }, error: function (xhr, textStatus, errorThrown) { errorCallback(SDK.JQuery._errorHandler(xhr)); } }); }, 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> this._stringParameterCheck(id, "SDK.JQuery.retrieveRecord requires the id parameter is a string."); ///<param name="type" type="String"> /// The Schema Name of the Entity type record to retrieve. /// For an Account record, use "Account" ///</param> this._stringParameterCheck(type, "SDK.JQuery.retrieveRecord requires the type parameter is a string."); ///<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> if (select != null) this._stringParameterCheck(select, "SDK.JQuery.retrieveRecord requires the select parameter is a string."); ///<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> if (expand != null) this._stringParameterCheck(expand, "SDK.JQuery.retrieveRecord requires the expand parameter is a string."); ///<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> this._callbackParameterCheck(successCallback, "SDK.JQuery.retrieveRecord requires the successCallback parameter is a function."); ///<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._callbackParameterCheck(errorCallback, "SDK.JQuery.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 + "&$expand=" + expand; } } $.ajax({ type: "GET", contentType: "application/json; charset=utf-8", datatype: "json", url: this._ODataPath() + type + "Set" + "(guid'" + id + "')" + systemQueryOptions, beforeSend: function (xhr) { //Specifying this header ensures that the results will be returned as JSON. xhr.setRequestHeader("Accept", "application/json"); }, success: function (data, textStatus, xhr) { //JQuery does not provide an opportunity to specify a date reviver so this code // parses the xhr.responseText rather than use the data parameter passed by JQuery. successCallback(JSON.parse(xhr.responseText, SDK.JQuery._dateReviver).d); }, error: function (xhr, textStatus, errorThrown) { errorCallback(SDK.JQuery._errorHandler(xhr)); } }); }, 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> this._stringParameterCheck(id, "SDK.JQuery.updateRecord requires the id parameter."); ///<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> this._parameterCheck(object, "SDK.JQuery.updateRecord requires the object parameter."); ///<param name="type" type="String"> /// The Schema Name of the Entity type record to retrieve. /// For an Account record, use "Account" ///</param> this._stringParameterCheck(type, "SDK.JQuery.updateRecord requires the type parameter."); ///<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> this._callbackParameterCheck(successCallback, "SDK.JQuery.updateRecord requires the successCallback is a function."); ///<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._callbackParameterCheck(errorCallback, "SDK.JQuery.updateRecord requires the errorCallback is a function."); var jsonEntity = window.JSON.stringify(object); $.ajax({ type: "POST", contentType: "application/json; charset=utf-8", datatype: "json", data: jsonEntity, url: this._ODataPath() + type + "Set" + "(guid'" + id + "')", beforeSend: function (xhr) { //Specifying this header ensures that the results will be returned as JSON. xhr.setRequestHeader("Accept", "application/json"); //Specify the HTTP method MERGE to update just the changes you are submitting. xhr.setRequestHeader("X-HTTP-Method", "MERGE"); }, success: function (data, textStatus, xhr) { //Nothing is returned to the success function successCallback(); }, error: function (xhr, textStatus, errorThrown) { errorCallback(SDK.JQuery._errorHandler(xhr)); } }); }, 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> this._stringParameterCheck(id, "SDK.JQuery.deleteRecord requires the id parameter."); ///<param name="type" type="String"> /// The Schema Name of the Entity type record to delete. /// For an Account record, use "Account" ///</param> this._stringParameterCheck(type, "SDK.JQuery.deleteRecord requires the type parameter."); ///<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> this._callbackParameterCheck(successCallback, "SDK.JQuery.deleteRecord requires the successCallback is a function."); ///<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._callbackParameterCheck(errorCallback, "SDK.JQuery.deleteRecord requires the errorCallback is a function."); $.ajax({ type: "POST", contentType: "application/json; charset=utf-8", datatype: "json", url: this._ODataPath() + type + "Set(guid'" + id + "')", beforeSend: function (XMLHttpRequest) { //Specifying this header ensures that the results will be returned as JSON. XMLHttpRequest.setRequestHeader("Accept", "application/json"); //Specify the HTTP method DELETE to perform a delete operation. XMLHttpRequest.setRequestHeader("X-HTTP-Method", "DELETE"); }, success: function (data, textStatus, xhr) { // Nothing is returned to the success function. successCallback(); }, error: function (xhr, textStatus, errorThrown) { errorCallback(SDK.JQuery._errorHandler(xhr)); } }); }, 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 records to retrieve /// For an Account record, use "Account" ///</param> this._stringParameterCheck(type, "SDK.JQuery.retrieveMultipleRecords requires the type parameter is a string."); ///<param name="options" type="String"> /// A String representing the OData System Query Options to control the data returned /// Do not include the $top option, use the top parameters to set the maximum number of records to return. ///</param> if (options != null) this._stringParameterCheck(options, "SDK.JQuery.retrieveMultipleRecords requires the options parameter is a string."); ///<param name="successCallback" type="Function"> /// The function that will be passed through and be called for each page of records returned. /// This function should loop through the results and push the records into an array. /// </param> this._callbackParameterCheck(successCallback, "SDK.JQuery.retrieveMultipleRecords requires the successCallback parameter is a function."); ///<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._callbackParameterCheck(errorCallback, "SDK.JQuery.retrieveMultipleRecords requires the errorCallback parameter is a function."); ///<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._callbackParameterCheck(OnComplete, "SDK.JQuery.retrieveMultipleRecords requires the OnComplete parameter is a function."); var optionsString; if (options != null) { if (options.charAt(0) != "?") { optionsString = "?" + options; } else { optionsString = options; } } $.ajax({ type: "GET", contentType: "application/json; charset=utf-8", datatype: "json", url: this._ODataPath() + type + "Set" + optionsString, beforeSend: function (XMLHttpRequest) { //Specifying this header ensures that the results will be returned as JSON. XMLHttpRequest.setRequestHeader("Accept", "application/json"); }, success: function (data, textStatus, xhr) { if (data && data.d && data.d.results) { successCallback(JSON.parse(xhr.responseText, SDK.JQuery._dateReviver).d.results); if (data.d.__next != null) { var queryOptions = data.d.__next.substring((SDK.JQuery._ODataPath() + type + "Set").length); SDK.JQuery.retrieveMultipleRecords(type, queryOptions, successCallback, errorCallback, OnComplete); } else { OnComplete(); } } }, error: function (xhr, textStatus, errorThrown) { errorCallback(SDK.JQuery._errorHandler(xhr)); } }); }, __namespace: true };
(三) Silverlight
Silverlight使用的都是异步操作。参见如何创建一个Silverlight 程序。
1. 返回少于50条记录
<UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class="SilverlightApplication2.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:SilverlightApplication2" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <StackPanel x:Name="MessagePanel" VerticalAlignment="Top"> <sdk:Label x:Name="myLabel" Content=""/> <sdk:DataGrid x:Name="myDataGrid" AutoGenerateColumns="False" IsReadOnly="True" > <sdk:DataGrid.Columns> <sdk:DataGridTextColumn x:Name="FirstNameColumn" Header="First Name" Binding="{Binding FirstName, Mode=OneTime}" /> <sdk:DataGridTextColumn x:Name="LastNameColumn" Header="Last Name" Binding="{Binding LastName, Mode=OneTime}" /> </sdk:DataGrid.Columns> </sdk:DataGrid> </StackPanel> </Grid> </UserControl>
using System; using System.Data.Services.Client; using System.Linq; using System.Threading; using System.Windows.Controls; using SilverlightApplication2.CrmODataService; using SilverlightApplication2.Utilities; namespace SilverlightApplication2 { public partial class MainPage : UserControl { private SynchronizationContext _syncContext; private escrmContext _context; private String _serverUrl; public MainPage() { InitializeComponent(); //Keeps a reference to the UI thread _syncContext = SynchronizationContext.Current; //Get the ServerUrl (ServerUrl is formatted differently OnPremise than OnLine) _serverUrl = ServerUtility.GetServerUrl(); if (!String.IsNullOrEmpty(_serverUrl)) { //Setup Context _context = new escrmContext(new Uri(String.Format("{0}/xrmservices/2011/organizationdata.svc/", _serverUrl), UriKind.Absolute)); //This is important because if the entity has new //attributes added the code will fail. _context.IgnoreMissingProperties = true; SearchContacts(); } else { //No ServerUrl was found. Display message. MessagePanel.Children.Add(new TextBlock() { Text = "Unable to access server url. Launch this Silverlight " + "Web Resource from a CRM Form OR host it in a valid " + "HTML Web Resource with a " + "<script src='ClientGlobalContext.js.aspx' " + "type='text/javascript'></script>" }); } } private void SearchContacts() { DataServiceQuery<Contact> query = (DataServiceQuery<Contact>)_context.ContactSet.Where(x => x.StateCode.Value.Value == 0); query.BeginExecute(OnContactSearchComplete, query); } private void OnContactSearchComplete(IAsyncResult result) { try { //Get the original query back from the result. DataServiceQuery<Contact> query = result.AsyncState as DataServiceQuery<Contact>; var itemsource = new DataServiceCollection<Contact>(query.EndExecute(result)); this.myDataGrid.ItemsSource = itemsource; myLabel.Content = "There are " + itemsource.Count + " contacts"; } catch (SystemException se) { _syncContext.Send(new SendOrPostCallback(showErrorDetails), se); } } private void showErrorDetails(object ex) { //Assure the control is visible MessagePanel.Visibility = System.Windows.Visibility.Visible; Exception exception = (Exception)ex; String type = exception.GetType().ToString(); MessagePanel.Children.Add(new TextBlock() { Text = String.Format("{0} Message: {1}", type, exception.Message) }); MessagePanel.Children.Add(new TextBlock() { Text = String.Format("Stack: {0}", exception.StackTrace) }); if (exception.InnerException != null) { String exceptType = exception.InnerException.GetType().ToString(); MessagePanel.Children.Add(new TextBlock() { Text = String.Format("InnerException: {0} : {1}", exceptType, exception.InnerException.Message) }); } } } }
2. 返回大于50条记录
<UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class="SilverlightApplication2.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <StackPanel x:Name="MessagePanel" VerticalAlignment="Top" Height="145"> <sdk:Label x:Name="myLabel" Content=""/> </StackPanel> <sdk:DataGrid x:Name="myDataGrid" AutoGenerateColumns="False" IsReadOnly="True" ScrollViewer.VerticalScrollBarVisibility="Visible" Margin="0,71,0,0"> <sdk:DataGrid.Columns> <sdk:DataGridTextColumn x:Name="FirstNameColumn" Header="First Name" Binding="{Binding FirstName, Mode=OneTime}" /> <sdk:DataGridTextColumn x:Name="LastNameColumn" Header="Last Name" Binding="{Binding LastName, Mode=OneTime}" /> </sdk:DataGrid.Columns> </sdk:DataGrid> </Grid> </UserControl>
using System; using System.Data.Services.Client; using System.Linq; using System.Threading; using System.Windows.Controls; using SilverlightApplication2.CrmODataService; using SilverlightApplication2.Utilities; namespace SilverlightApplication2 { public partial class MainPage : UserControl { private SynchronizationContext _syncContext; private escrmContext _context; private String _serverUrl; public DataServiceCollection<Contact> ContactCollection; public MainPage() { InitializeComponent(); //Keeps a reference to the UI thread _syncContext = SynchronizationContext.Current; //Get the ServerUrl (ServerUrl is formatted differently OnPremise than OnLine) _serverUrl = ServerUtility.GetServerUrl(); if (!String.IsNullOrEmpty(_serverUrl)) { //Setup Context _context = new escrmContext(new Uri(String.Format("{0}/xrmservices/2011/organizationdata.svc/", _serverUrl), UriKind.Absolute)); //This is important because if the entity has new //attributes added the code will fail. _context.IgnoreMissingProperties = true; SearchContacts(); } else { //No ServerUrl was found. Display message. MessagePanel.Children.Add(new TextBlock() { Text = "Unable to access server url. Launch this Silverlight " + "Web Resource from a CRM Form OR host it in a valid " + "HTML Web Resource with a " + "<script src='ClientGlobalContext.js.aspx' " + "type='text/javascript'></script>" }); } } private void SearchContacts() { DataServiceQuery<Contact> query = (DataServiceQuery<Contact>)_context.ContactSet.AddQueryOption("$select", "FirstName,LastName").Where(x => x.StateCode.Value.Value == 0); query.BeginExecute(ProcessPages<Contact>, new PagingContext<Contact>() { ServiceContext = _context, Query = query, PageProcessor = delegate(DataServiceCollection<Contact> results) { try { if (null == ContactCollection) { ContactCollection = new DataServiceCollection<Contact>(_context); ContactCollection.Load(results); } else { for (int i = 0; i < results.Count; i++) { ContactCollection.Add(results[i]); } } myLabel.Content = "There are " + ContactCollection.Count + " contacts"; this.myDataGrid.ItemsSource = ContactCollection; } catch (Exception ex) { _syncContext.Send(new SendOrPostCallback(showErrorDetails), ex); } return true; } }); } private void ProcessPages<T>(IAsyncResult result) { try { PagingContext<T> context = (PagingContext<T>)result.AsyncState; QueryOperationResponse<T> response; if (null == context.Query) { response = (QueryOperationResponse<T>)context.ServiceContext.EndExecute<T>(result); } else { response = (QueryOperationResponse<T>)context.Query.EndExecute(result); context.Query = null; } DataServiceCollection<T> results = new DataServiceCollection<T>(response); if (null != context.PageProcessor && !context.PageProcessor(results)) { //Stop processing return; } DataServiceQueryContinuation<T> token = results.Continuation; if (null == token) { System.Windows.MessageBox.Show("complete"); return; } context.ServiceContext.BeginExecute(token, ProcessPages<T>, context); } catch (Exception ex) { throw ex; } } private void showErrorDetails(object ex) { //Assure the control is visible MessagePanel.Visibility = System.Windows.Visibility.Visible; Exception exception = (Exception)ex; String type = exception.GetType().ToString(); MessagePanel.Children.Add(new TextBlock() { Text = String.Format("{0} Message: {1}", type, exception.Message) }); MessagePanel.Children.Add(new TextBlock() { Text = String.Format("Stack: {0}", exception.StackTrace) }); if (exception.InnerException != null) { String exceptType = exception.InnerException.GetType().ToString(); MessagePanel.Children.Add(new TextBlock() { Text = String.Format("InnerException: {0} : {1}", exceptType, exception.InnerException.Message) }); } } } sealed class PagingContext<T> { public DataServiceContext ServiceContext { get; set; } public DataServiceQuery<T> Query { get; set; } public Func<DataServiceCollection<T>, bool> PageProcessor { get; set; } } }
(四) LINQ
using System; using Microsoft.Xrm.Sdk.Discovery; using Microsoft.Xrm.Sdk.Client; using System.Configuration; using Microsoft.Xrm.Sdk; using Microsoft.Crm.Sdk.Messages; using System.Linq; namespace CRM.LINQTest { class Program { static void Main(string[] args) { string _discoveryServiceAddress = ConfigurationManager.AppSettings["DiscoveryServiceAddress"]; IServiceManagement<IDiscoveryService> serviceManagement = ServiceConfigurationFactory.CreateManagement<IDiscoveryService>(new Uri(_discoveryServiceAddress)); AuthenticationProviderType endpointType = serviceManagement.AuthenticationType; AuthenticationCredentials authCredentials = GetCredentials(endpointType); String organizationUri = ConfigurationManager.AppSettings["OrganizationServiceAddress"]; if (!String.IsNullOrWhiteSpace(organizationUri)) { IServiceManagement<IOrganizationService> orgServiceManagement = ServiceConfigurationFactory.CreateManagement<IOrganizationService>(new Uri(organizationUri)); // Set the credentials. AuthenticationCredentials credentials = GetCredentials(endpointType); // Get the organization service proxy. using (OrganizationServiceProxy organizationProxy = GetProxy<IOrganizationService, OrganizationServiceProxy>(orgServiceManagement, credentials)) { // This statement is required to enable early-bound type support. organizationProxy.EnableProxyTypes(); IOrganizationService _service = (IOrganizationService)organizationProxy; ServiceContext svcContext = new ServiceContext(_service); var accounts = (from a in svcContext.AccountSet select new Account() { Name = a.Name, }).ToArray(); int i = 1; foreach (var a in accounts) { Console.WriteLine(string.Format("{0}/{2}: {1}", i, a.Name, accounts.Count())); i++; } } } } private static AuthenticationCredentials GetCredentials(AuthenticationProviderType endpointType) { string _userName = ConfigurationManager.AppSettings["UserName"]; string _password = ConfigurationManager.AppSettings["Password"]; string _domain = ConfigurationManager.AppSettings["Domain"]; AuthenticationCredentials authCredentials = new AuthenticationCredentials(); switch (endpointType) { case AuthenticationProviderType.ActiveDirectory: authCredentials.ClientCredentials.Windows.ClientCredential = new System.Net.NetworkCredential(_userName, _password, _domain); break; case AuthenticationProviderType.Federation: case AuthenticationProviderType.OnlineFederation: authCredentials.ClientCredentials.UserName.UserName = _userName; authCredentials.ClientCredentials.UserName.Password = _password; break; default: break; } return authCredentials; } private static TProxy GetProxy<TService, TProxy>(IServiceManagement<TService> serviceManagement, AuthenticationCredentials authCredentials) where TService : class where TProxy : ServiceProxy<TService> { Type classType = typeof(TProxy); if (serviceManagement.AuthenticationType != AuthenticationProviderType.ActiveDirectory) { AuthenticationCredentials tokenCredentials = serviceManagement.Authenticate(authCredentials); // Obtain discovery/organization service proxy for Federated, LiveId and OnlineFederated environments. // Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and SecurityTokenResponse. return (TProxy)classType .GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(SecurityTokenResponse) }) .Invoke(new object[] { serviceManagement, tokenCredentials.SecurityTokenResponse }); } // Obtain discovery/organization service proxy for ActiveDirectory environment. // Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and ClientCredentials. return (TProxy)classType .GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(System.ServiceModel.Description.ClientCredentials) }) .Invoke(new object[] { serviceManagement, authCredentials.ClientCredentials }); } } }
(五) FetchXML
using System; using Microsoft.Xrm.Sdk.Discovery; using Microsoft.Xrm.Sdk.Client; using System.Configuration; using Microsoft.Xrm.Sdk; using Microsoft.Crm.Sdk.Messages; using System.Linq; using System.IO; using System.Xml; using System.Text; namespace CRM.FetchXMLTest { class Program { private static string CreateXml(string xml, int page) { StringReader stringReader = new StringReader(xml); XmlTextReader reader = new XmlTextReader(stringReader); // Load document XmlDocument doc = new XmlDocument(); doc.Load(reader); return CreateXml(doc, page); } private static string CreateXml(XmlDocument doc, int page) { XmlAttributeCollection attrs = doc.DocumentElement.Attributes; XmlAttribute pageAttr = doc.CreateAttribute("page"); pageAttr.Value = System.Convert.ToString(page); attrs.Append(pageAttr); StringBuilder sb = new StringBuilder(1024); StringWriter stringWriter = new StringWriter(sb); XmlTextWriter writer = new XmlTextWriter(stringWriter); doc.WriteTo(writer); writer.Close(); return sb.ToString(); } static void Main(string[] args) { string _discoveryServiceAddress = ConfigurationManager.AppSettings["DiscoveryServiceAddress"]; IServiceManagement<IDiscoveryService> serviceManagement = ServiceConfigurationFactory.CreateManagement<IDiscoveryService>(new Uri(_discoveryServiceAddress)); AuthenticationProviderType endpointType = serviceManagement.AuthenticationType; AuthenticationCredentials authCredentials = GetCredentials(endpointType); String organizationUri = ConfigurationManager.AppSettings["OrganizationServiceAddress"]; if (!String.IsNullOrWhiteSpace(organizationUri)) { IServiceManagement<IOrganizationService> orgServiceManagement = ServiceConfigurationFactory.CreateManagement<IOrganizationService>(new Uri(organizationUri)); // Set the credentials. AuthenticationCredentials credentials = GetCredentials(endpointType); // Get the organization service proxy. using (OrganizationServiceProxy organizationProxy = GetProxy<IOrganizationService, OrganizationServiceProxy>(orgServiceManagement, credentials)) { //organizationProxy.Timeout = new TimeSpan(1, 0, 0, 0); string fetch2 = @"<fetch mapping='logical'> <entity name='account'> <attribute name='accountid'/> <attribute name='name'/> </entity> </fetch> "; int i = 1; // Initialize the page number. int pageNumber = 1; while (true) { // Build fetchXml string with the placeholders. string xml = CreateXml(fetch2, pageNumber); EntityCollection returnCollection = organizationProxy.RetrieveMultiple(new Microsoft.Xrm.Sdk.Query.FetchExpression(xml)); foreach (var a in returnCollection.Entities) { Console.WriteLine(string.Format("{0}: {1}", i, a["name"])); i++; } // Check for morerecords, if it returns 1. if (returnCollection.MoreRecords) { // Increment the page number to retrieve the next page. pageNumber++; } else { // If no more records in the result nodes, exit the loop. break; } } } } } private static AuthenticationCredentials GetCredentials(AuthenticationProviderType endpointType) { string _userName = ConfigurationManager.AppSettings["UserName"]; string _password = ConfigurationManager.AppSettings["Password"]; string _domain = ConfigurationManager.AppSettings["Domain"]; AuthenticationCredentials authCredentials = new AuthenticationCredentials(); switch (endpointType) { case AuthenticationProviderType.ActiveDirectory: authCredentials.ClientCredentials.Windows.ClientCredential = new System.Net.NetworkCredential(_userName, _password, _domain); break; case AuthenticationProviderType.Federation: case AuthenticationProviderType.OnlineFederation: authCredentials.ClientCredentials.UserName.UserName = _userName; authCredentials.ClientCredentials.UserName.Password = _password; break; default: break; } return authCredentials; } private static TProxy GetProxy<TService, TProxy>(IServiceManagement<TService> serviceManagement, AuthenticationCredentials authCredentials) where TService : class where TProxy : ServiceProxy<TService> { Type classType = typeof(TProxy); if (serviceManagement.AuthenticationType != AuthenticationProviderType.ActiveDirectory) { AuthenticationCredentials tokenCredentials = serviceManagement.Authenticate(authCredentials); // Obtain discovery/organization service proxy for Federated, LiveId and OnlineFederated environments. // Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and SecurityTokenResponse. return (TProxy)classType .GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(SecurityTokenResponse) }) .Invoke(new object[] { serviceManagement, tokenCredentials.SecurityTokenResponse }); } // Obtain discovery/organization service proxy for ActiveDirectory environment. // Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and ClientCredentials. return (TProxy)classType .GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(System.ServiceModel.Description.ClientCredentials) }) .Invoke(new object[] { serviceManagement, authCredentials.ClientCredentials }); } } }
Retrieve所有记录
private static List<Entity> GetAllAccounts(OrganizationServiceProxy organizationProxy) { string fetch2 = @"<fetch mapping='logical'> <entity name='account'> <attribute name='accountid'/> <attribute name='name'/> </entity> </fetch> "; List<Entity> result = new List<Entity>(); // Initialize the page number. int pageNumber = 1; while (true) { // Build fetchXml string with the placeholders. string xml = CreateXml(fetch2, pageNumber); EntityCollection returnCollection = organizationProxy.RetrieveMultiple(new Microsoft.Xrm.Sdk.Query.FetchExpression(xml)); foreach (var a in returnCollection.Entities) { result.Add(a); } // Check for morerecords, if it returns 1. if (returnCollection.MoreRecords) { // Increment the page number to retrieve the next page. pageNumber++; } else { // If no more records in the result nodes, exit the loop. break; } } return result; }
(六) Query Expression
// Get the organization service proxy. using (OrganizationServiceProxy organizationProxy = GetProxy<IOrganizationService, OrganizationServiceProxy>(orgServiceManagement, credentials)) { Microsoft.Xrm.Sdk.Query.QueryExpression query = new Microsoft.Xrm.Sdk.Query.QueryExpression { EntityName = "account", ColumnSet = new ColumnSet("name") }; int i = 1; query.PageInfo = new PagingInfo(); query.PageInfo.PageNumber = 1; query.PageInfo.PagingCookie = null; while (true) { // Retrieve the page. EntityCollection ec = organizationProxy.RetrieveMultiple(query); if (ec.Entities != null) { // Retrieve all records from the result set. foreach (var a in ec.Entities) { Console.WriteLine(string.Format("{0}: {1}", i, a["name"])); i++; } } // Check for more records, if it returns true. if (ec.MoreRecords) { // Increment the page number to retrieve the next page. query.PageInfo.PageNumber++; // Set the paging cookie to the paging cookie returned from current results. query.PageInfo.PagingCookie = ec.PagingCookie; } else { // If no more records are in the result nodes, exit the loop. break; } } }
Retrieve所有记录
private static List<Entity> GetAllAccounts(OrganizationServiceProxy organizationProxy) { List<Entity> result = new List<Entity>(); Microsoft.Xrm.Sdk.Query.QueryExpression query = new Microsoft.Xrm.Sdk.Query.QueryExpression { EntityName = "account", ColumnSet = new ColumnSet("name") }; int i = 1; query.PageInfo = new PagingInfo(); query.PageInfo.PageNumber = 1; query.PageInfo.PagingCookie = null; while (true) { // Retrieve the page. EntityCollection ec = organizationProxy.RetrieveMultiple(query); if (ec.Entities != null) { // Retrieve all records from the result set. foreach (var a in ec.Entities) { result.Add(a); } } // Check for more records, if it returns true. if (ec.MoreRecords) { // Increment the page number to retrieve the next page. query.PageInfo.PageNumber++; // Set the paging cookie to the paging cookie returned from current results. query.PageInfo.PagingCookie = ec.PagingCookie; } else { // If no more records are in the result nodes, exit the loop. break; } } return result; }