{"id":20330,"date":"2019-08-23T12:27:39","date_gmt":"2019-08-23T12:27:39","guid":{"rendered":"https:\/\/www.inogic.com\/blog\/?p=20330"},"modified":"2022-07-21T12:13:30","modified_gmt":"2022-07-21T06:43:30","slug":"execute-multiple-fetchxml-and-odata-queries-using-batch-request","status":"publish","type":"post","link":"https:\/\/www.inogic.com\/blog\/2019\/08\/execute-multiple-fetchxml-and-odata-queries-using-batch-request\/","title":{"rendered":"Execute multiple FetchXML and OData queries using Batch request"},"content":{"rendered":"<p style=\"text-align: justify;\">We have developed an application to fulfill one of our clients\u2019 requirement. In that application we have perform multiple retrieval operation from CRM (around 10) either using FetchXML or OData of different entities. So, when we retrieve records from Dynamics 365 CRM of different entities for each retrieve operation it takes around 300 milliseconds and thus our application takes time to load and users have to wait for application to load. For this, our clients reported that the application is slow and taking time to load and operate, so ultimately it takes time in displaying result to the users. As it is, quick turnaround time is essential for a business. Therefore, to improve the performance, we worked on it and found that most of the time it was taking was to retrieve records from Dynamics CRM as we perform multiple retrieval operation. To reduce this retrieval time, we have used Batch request and retrieved multiple records using single request instead of multiple requests thereby reducing significant amount of time.<\/p>\n<p>Below is the JavaScript code used for same.<\/p>\n<p>We have created this function to execute four retrieval requests in single instance to retrieve records from Dynamics CRM instead of four different requests.<\/p>\n<p>\/\/This function is used to read batch records from CRM<\/p>\n<p>var readRecordsUsingBatchRequest = function (entityType, webresourceName) {<\/p>\n<p>var functionName = &#8220;readRecordsUsingBatchRequest &#8220;;<\/p>\n<p>var batchReq = [];<\/p>\n<p>var team = &#8220;Sales&#8221;;<\/p>\n<p>var userId = &#8220;&#8221;;<\/p>\n<p>var languagecode = &#8220;1033&#8221;;<\/p>\n<p>try {<\/p>\n<p>\/\/get the userid<\/p>\n<p>userId = getUserId().replace(&#8220;{&#8220;, &#8220;&#8221;).replace(&#8220;}&#8221;, &#8220;&#8221;);<\/p>\n<p><strong>\/\/Read system user\u00a0\u00a0\u00a0\u00a0 <\/strong><\/p>\n<p>fetchXml = &#8220;&lt;fetch version=&#8217;1.0&#8242; output-format=&#8217;xml-platform&#8217; mapping=&#8217;logical&#8217; distinct=&#8217;true&#8217;&gt;&#8221; +<\/p>\n<p>&#8220;&lt;entity name=&#8217;systemuser&#8217;&gt;&#8221; +<\/p>\n<p>&#8220;&lt;attribute name=&#8217;fullname&#8217; \/&gt;&#8221; +<\/p>\n<p>&#8220;&lt;attribute name=&#8217;businessunitid&#8217; \/&gt;&#8221; +<\/p>\n<p>&#8220;&lt;attribute name=&#8217;systemuserid&#8217; \/&gt;&#8221; +<\/p>\n<p>&#8220;&lt;link-entity name=&#8217;teammembership&#8217; from=&#8217;systemuserid&#8217; to=&#8217;systemuserid&#8217; visible=&#8217;false&#8217; intersect=&#8217;true&#8217;&gt;&#8221; +<\/p>\n<p>&#8220;&lt;link-entity name=&#8217;team&#8217; from=&#8217;teamid&#8217; to=&#8217;teamid&#8217; alias=&#8217;team&#8217;&gt;&#8221; +<\/p>\n<p>&#8220;&lt;attribute name=&#8217;name&#8217; \/&gt;&#8221; +<\/p>\n<p>&#8220;&lt;attribute name=&#8217;teamid&#8217; \/&gt;&#8221; +<\/p>\n<p>&#8220;&lt;filter type=&#8217;and&#8217;&gt;&#8221; +<\/p>\n<p>&#8220;&lt;condition attribute=&#8217;name&#8217; operator=&#8217;eq&#8217; value='&#8221; + team.toLowerCase() + &#8220;&#8216; \/&gt;&#8221; +<\/p>\n<p>&#8220;&lt;\/filter&gt;&#8221; +<\/p>\n<p>&#8220;&lt;\/link-entity&gt;&#8221; +<\/p>\n<p>&#8220;&lt;\/link-entity&gt;&#8221; +<\/p>\n<p>&#8220;&lt;\/entity&gt;&#8221; +<\/p>\n<p>&#8220;&lt;\/fetch&gt;&#8221;;<\/p>\n<p>var req = {};<\/p>\n<p>req.Query = fetchXml;<\/p>\n<p>req.IsFetchxml = true;<\/p>\n<p>req.EntitysetName = &#8220;systemusers&#8221;;<\/p>\n<p>batchReq.push(req);<\/p>\n<p><strong>\/\/Read Language webresource <\/strong><\/p>\n<p>var req = {};<\/p>\n<p>webresourceName = &#8220;new_LanguageLables_&#8221; + languagecode + &#8220;.xml&#8221;;<\/p>\n<p>req.Query = &#8220;?$select=webresourceid,content&amp;$filter=name eq &#8216;&#8221; + webresourceName + &#8220;&#8216; &#8220;;<\/p>\n<p>req.EntitysetName = &#8220;webresourceset&#8221;;<\/p>\n<p>batchReq.push(req);<\/p>\n<p><strong>\/\/Read usage (custom entity) records<\/strong><\/p>\n<p>fetchxml = &#8220;&lt;fetch version=&#8217;1.0&#8242; output-format=&#8217;xml-platform&#8217; mapping=&#8217;logical&#8217; distinct=&#8217;false&#8217;&gt;&#8221; +<\/p>\n<p>&#8220;&lt;entity name=&#8217;new_usage&#8217;&gt;&#8221; +<\/p>\n<p>&#8220;&lt;attribute name=&#8217;new_usageid&#8217; \/&gt;&#8221; +<\/p>\n<p>&#8220;&lt;attribute name=&#8217;new_currentcount&#8217; \/&gt;&#8221; +<\/p>\n<p>&#8220;&lt;attribute name=&#8217;new_allowedlimit&#8217; \/&gt;&#8221; +<\/p>\n<p>&#8220;&lt;filter type=&#8217;and&#8217;&gt;&#8221; +<\/p>\n<p>&#8220;&lt;condition attribute=&#8217;statecode&#8217; operator=&#8217;eq&#8217; value=&#8217;0&#8242; \/&gt;&#8221; +<\/p>\n<p>&#8220;&lt;\/filter&gt;&#8221; +<\/p>\n<p>&#8220;&lt;\/entity&gt;&#8221; +<\/p>\n<p>&#8220;&lt;\/fetch&gt;&#8221;;<\/p>\n<p>var req = {};<\/p>\n<p>req.Query = fetchxml;<\/p>\n<p>req.IsFetchxml = true;<\/p>\n<p>req.EntitysetName = &#8220;new_usages&#8221;;<\/p>\n<p>batchReq.push(req);<\/p>\n<p><strong>\/\/Read System views<\/strong><\/p>\n<p>var req = {};<\/p>\n<p>req.Query = &#8220;?$select=name,fetchxml,savedqueryid,layoutxml&amp;$filter=querytype eq 0 and isquickfindquery eq false and statecode eq 0 and returnedtypecode eq\u00a0 &#8216;&#8221; + entityType + &#8220;&#8216;&#8221;;<\/p>\n<p>req.EntitysetName = &#8220;savedqueries&#8221;;<\/p>\n<p>batchReq.push(req);<\/p>\n<p>\/\/retrieve using batch request<\/p>\n<p>WebApiLib.batchRequestRetrieve(batchReq, function (results) {<\/p>\n<p>readRecordsUsingBatchRequestCallback(result)<\/p>\n<p>}, readRecordsUsingBatchRequestErrorCallBack);<\/p>\n<p>} catch (e) {<\/p>\n<p>showError(functionName + &#8221; &#8221; + e.message);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>var readRecordsUsingBatchRequestCallback = function (error) {<\/p>\n<p>var functionName = &#8220;readRecordsUsingBatchRequestCallback &#8220;;<\/p>\n<p>try {<\/p>\n<p>\/\/Perform the required logic<\/p>\n<p>} catch (e) {<\/p>\n<p>showError(functionName + &#8221; &#8221; + e.message);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>var readRecordsUsingBatchRequestErrorCallBack = function (error) {<\/p>\n<p>var functionName = &#8220;readRecordsUsingBatchRequestCallback &#8220;;<\/p>\n<p>try {<\/p>\n<p>showError(functionName + &#8221; &#8221; + e.message);<\/p>\n<p>} catch (e) {<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>In WebApi library we have written below function to execute all the above queries to retrieve records using Ajax request. When we execute the request then it gives results in following format.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter size-full wp-image-20329\" style=\"border: 1px solid #0a0a0a; padding: 1px; margin: 1px;\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2019\/08\/Execute-multiple-FetchXML-and-OData-queries-using-Batch-request.png\" alt=\"Execute multiple FetchXML and OData queries using Batch request\" width=\"1179\" height=\"475\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2019\/08\/Execute-multiple-FetchXML-and-OData-queries-using-Batch-request.png 1179w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2019\/08\/Execute-multiple-FetchXML-and-OData-queries-using-Batch-request-300x121.png 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2019\/08\/Execute-multiple-FetchXML-and-OData-queries-using-Batch-request-768x309.png 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2019\/08\/Execute-multiple-FetchXML-and-OData-queries-using-Batch-request-1024x413.png 1024w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2019\/08\/Execute-multiple-FetchXML-and-OData-queries-using-Batch-request-660x266.png 660w\" sizes=\"(max-width: 1179px) 100vw, 1179px\" \/><\/p>\n<p>Now, our next challenge is to parse above response and get the results in JSON format.<\/p>\n<p>To parse the above response first we split this result using \u201cbatch\u201d word and slice it as shown in below.<\/p>\n<p><em>data.split(<\/em><em>&#8220;&#8211;batch&#8221;<\/em><em>).slice(1, reqCount + 1);<\/em><\/p>\n<p>Once we split, we get the array then looping through that array get the result of individual using<\/p>\n<p><em>result = value.substring(value.indexOf(<\/em><em>&#8216;{&#8216;<\/em><em>), value.lastIndexOf(<\/em><em>&#8216;}&#8217;<\/em><em>) + 1);<\/em><\/p>\n<p>And finally parse that result to get it JSON format using following line of code.<\/p>\n<p><em>\u00a0<\/em><em>JSON.parse(result)<\/em><\/p>\n<p><strong>\/\/Retrieval function in web api library<\/strong><\/p>\n<p>batchRequestRetrieve: function (requests, batchRequestRetrieveSuccess, batchRequestRetrieveError) {<\/p>\n<p>var reqColl = [];<\/p>\n<p>var reqCount = 0;<\/p>\n<p>try {<\/p>\n<p>reqCount = requests.length;<\/p>\n<p>\/\/encode the fetchxml<\/p>\n<p>$.each(requests, function (index, req) {<\/p>\n<p>reqColl.push(&#8216;&#8211;batch_fetch&#8217;);<\/p>\n<p>reqColl.push(&#8216;Content-Type: application\/http&#8217;);<\/p>\n<p>reqColl.push(&#8216;Content-Transfer-Encoding: binary&#8217;);<\/p>\n<p>reqColl.push(&#8221;);<\/p>\n<p>if (req.IsFetchxml != undefined &amp;&amp; req.IsFetchxml == true) {<\/p>\n<p>reqColl.push(&#8216;GET &#8216; + getWebAPIPath() + req.EntitysetName + &#8216;?fetchXml=&#8217; + req.Query + &#8216; HTTP\/1.1&#8217;);<\/p>\n<p>}<\/p>\n<p>else if (req.FunctionName != undefined) {<\/p>\n<p>reqColl.push(&#8216;GET &#8216; + getWebAPIPath() + req.FunctionName + &#8216; HTTP\/1.1&#8217;);<\/p>\n<p>}<\/p>\n<p>else {<\/p>\n<p>reqColl.push(&#8216;GET &#8216; + getWebAPIPath() + req.EntitysetName + req.Query + &#8216; HTTP\/1.1&#8217;);<\/p>\n<p>}<\/p>\n<p>reqColl.push(&#8216;Content-Type: application\/json&#8217;);<\/p>\n<p>reqColl.push(&#8216;OData-Version: 4.0&#8217;);<\/p>\n<p>reqColl.push(&#8216;OData-MaxVersion: 4.0&#8217;);<\/p>\n<p>reqColl.push(&#8216;Prefer: odata.include-annotations=*&#8217;);<\/p>\n<p>reqColl.push(&#8221;);<\/p>\n<p>reqColl.push(&#8216;{}&#8217;);<\/p>\n<p>});<\/p>\n<p>reqColl.push(&#8216;&#8211;batch_fetch&#8211;&#8216;);<\/p>\n<p>var mainReq = reqColl.join(&#8216;\\r\\n&#8217;);<\/p>\n<p>\/\/create AJAX request<\/p>\n<p>$.ajax({<\/p>\n<p>type: &#8220;POST&#8221;,<\/p>\n<p>contentType: &#8220;application\/json; charset=utf-8&#8221;,<\/p>\n<p>datatype: &#8220;json&#8221;,<\/p>\n<p>async: true,<\/p>\n<p>url: this.getWebAPIPath() + &#8220;$batch&#8221;,<\/p>\n<p>data: mainReq,<\/p>\n<p>beforeSend: function (xhr) {<\/p>\n<p>\/\/Specifying this header ensures that the results will be returned as JSON.<\/p>\n<p>xhr.setRequestHeader(&#8220;Accept&#8221;, &#8220;application\/json&#8221;);<\/p>\n<p>xhr.setRequestHeader(&#8220;OData-MaxVersion&#8221;, &#8220;4.0&#8221;);<\/p>\n<p>xhr.setRequestHeader(&#8220;OData-Version&#8221;, &#8220;4.0&#8221;);<\/p>\n<p>xhr.setRequestHeader(&#8220;Prefer&#8221;, &#8220;odata.include-annotations=*&#8221;);<\/p>\n<p>xhr.setRequestHeader(&#8220;Content-Type&#8221;, &#8220;multipart\/mixed;boundary=batch_fetch&#8221;);<\/p>\n<p>},<\/p>\n<p>success: function (data, textStatus, xhr) {<\/p>\n<p>var results = data.split(&#8220;&#8211;batch&#8221;).slice(1, reqCount + 1);<\/p>\n<p>var recCollection = [];<\/p>\n<p>$.each(results, function (index, data) {<\/p>\n<p>var result = getFormattedData(data);<\/p>\n<p>if (JSON.parse(result).value != undefined) {<\/p>\n<p>recCollection.push(JSON.parse(result).value);<\/p>\n<p>}<\/p>\n<p>else {<\/p>\n<p>recCollection.push(JSON.parse(result));<\/p>\n<p>}<\/p>\n<p>});<\/p>\n<p>batchRequestRetrieveSuccess(recCollection);<\/p>\n<p>},<\/p>\n<p>error: function (xhr, textStatus, errorThrown) {<\/p>\n<p>batchRequestRetrieveError(xhr);<\/p>\n<p>}<\/p>\n<p>});<\/p>\n<p>} catch (e) {<\/p>\n<p>throw new Error(e);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>getWebAPIPath: function () {<\/p>\n<p>return this.getClientUrl() + &#8220;\/api\/data\/v9.1\/&#8221;;<\/p>\n<p>}<\/p>\n<p>getFormattedData: function (value) {<\/p>\n<p>return value.substring(value.indexOf(&#8216;{&#8216;), value.lastIndexOf(&#8216;}&#8217;) + 1);<\/p>\n<p>}<\/p>\n<h2><strong>Conclusion<\/strong><\/h2>\n<p>With the help of Batch request we can execute multiple Fetch and OData queries to get the results. This increases the performance and reduces the retrieval time.<\/p>\n<h2 style=\"text-align: left;\"><div class=\"su-heading su-heading-style-default su-heading-align-center\" id=\"\" style=\"font-size:15px;margin-bottom:5px\"><div class=\"su-heading-inner\">70% of global 2000 companies apply gamification to improve productivity and returns!<\/div><\/div><\/h2>\n<p><em><strong><a href=\"https:\/\/bit.ly\/3RD4lYW\" target=\"_blank\" rel=\"noopener noreferrer\">Gamifics365<\/a> <\/strong>\u2013 Spin the magic of games within Microsoft Dynamics 365 CRM to improve user adoption, enhance productivity, and achieve company goals!<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>We have developed an application to fulfill one of our clients\u2019 requirement. In that application we have perform multiple retrieval operation from CRM (around 10) either using FetchXML or OData of different entities. So, when we retrieve records from Dynamics 365 CRM of different entities for each retrieve operation it takes around 300 milliseconds and\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.inogic.com\/blog\/2019\/08\/execute-multiple-fetchxml-and-odata-queries-using-batch-request\/\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":13,"featured_media":20331,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13,15],"tags":[795],"class_list":["post-20330","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-customizations","category-development","tag-fetchxml"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts\/20330","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/users\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/comments?post=20330"}],"version-history":[{"count":0,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts\/20330\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/media\/20331"}],"wp:attachment":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/media?parent=20330"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/categories?post=20330"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/tags?post=20330"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}