トピックス

知識創造研究室 by CRM(xRM)

Dynamics 365(Dynamics CRM)Web API レコード取得編 Part.Ⅴ

みなさん、ちゃーっす!
夏バテで『ピノ チョコアソート』を食べ倒してる Harada です。
アーモンドが一番好きです!(*`・へ・´*)ドヤァ

さて、今回はご要望頂きましたレコード取得時のページングとFetchXML の実行とページングについて書かせてもらおうと思います。

Dynamics 365 レコード取得 ページング

Web API でレコードを取得する場合、ページングをしない場合は最大5,000件という制限があります。取得するフィールド数や処理する側のスペックにもよりますが、一度に5,000件取得するとクライアント側の処理に時間がかかり、パフォーマンスの問題となることがあります。
そこで、ページングが必要となります。ページングとは、5,000件のデータを1,000件ずつ5回取得することを言います。
なんとなくページングについてご理解いただけましたか?理解できた方も理解できなかった方も下記のサンプルを確認してください(笑)

var apiUrl = "https://<ORG>.crm7.dynamics.com/api/data/v8.2/incidents";
var s = '$select=casetypecode,checkemail,_customerid_value,description,';
s += 'exchangerate,followupby,influencescore,numberofchildincidents,';
s += '_owninguser_value,statecode,statuscode,ticketnumber,title,versionnumber';
// 実行
execute(encodeURI(apiUrl + '?' + s));function execute(requestUrl) {
var xhr = new XMLHttpRequest();
xhr.open("GET", requestUrl, true);
xhr.setRequestHeader('Accept', 'application/json');
xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
xhr.setRequestHeader('OData-MaxVersion', '4.0');
xhr.setRequestHeader('OData-Version', '4.0');
// 1ページあたりのレコード数を指定
xhr.setRequestHeader('Prefer', 'odata.include-annotations="*",odata.maxpagesize=10');
xhr.onreadystatechange = function () {
if (this.readyState == 4) {
if (this.status == 200) {
console.log(this.response);
var data = JSON.parse(this.response);
// さらにレコードがある場合に再帰
if (data["@odata.nextLink"])
execute(data["@odata.nextLink"]);
} else {
var error = JSON.parse(this.response).error;
Xrm.Utility.alertDialog(error.message, function () { });
}
}
};
xhr.send();
}

さて、以前までの分と何が違うのでしょうか・・・簡単に説明します。

1行目 ~ 4行目
レコード取得のURLを作成しています。ここは、以前と変わりないですね。
6行目
この行の下で定義している function を呼び出しています。
16行目
1度に取得するレコード数を指定しています。ここでは1度のリクエストで10件返すように指定しています。
23行目、24行目
さらにレコードがあるかどうかは、戻ってきたデータ『@odata.nextLink』にURLが入っているためこちらで再度リクエストします。

意外と簡単だと思いませんか?ただ、ページ番号を指定して取得することが簡単にできそうにないという点が残念です。

Dynamics 365 レコード取得 FetchXMLの実行

つづいて、以前簡単に触れたFetchXMLの実行です。FetchXMLなので、集計にしようかと思ったのですが、ページングのほうが難しそうだったので、ここではFetchXMLでのページングのサンプルを記載します。それではご覧あれ~!


var apiUrl = "https://<ORG>.crm7.dynamics.com/api/data/v8.2/incidents";
var page = 1; // ページを指定
var count = 10; // 1ページあたりのレコード数を指定
// fetch エレメント の子エレメントを定義
var xml = '<entity name="incident" ><attribute name="ticketnumber" />';
xml += '<attribute name="title" /><attribute name="exchangerate" />';
xml += '<attribute name="checkemail" /><attribute name="casetypecode" />';
xml += '<attribute name="statuscode" /><attribute name="versionnumber" />';
xml += '<attribute name="owninguser" /><attribute name="customerid" />';
xml += '<attribute name="statecode" /><attribute name="numberofchildincidents" />';
xml += '<attribute name="followupby" /><attribute name="influencescore" />';
xml += '<attribute name="description" /></entity>';
// 実行
executeFetchXml(apiUrl, xml, page, count);function executeFetchXml(apiUrl, fetch, page, count, pagingCookie) {
// fetchXml を作成
var fetchXml = 'fetchXml=<fetch';
fetchXml += ' page="' + page + '"';
fetchXml += ' count="' + count + '"';
if (pagingCookie) {
fetchXml += " " + escape(pagingCookie);
}
fetchXml += '>' + fetch + '</fetch>';

var xhr = new XMLHttpRequest();
xhr.open("GET", encodeURI(apiUrl + "?" + fetchXml), true);
xhr.setRequestHeader('Accept', 'application/json');
xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
xhr.setRequestHeader('OData-MaxVersion', '4.0');
xhr.setRequestHeader('OData-Version', '4.0');
// ページング用の注釈を指定。
xhr.setRequestHeader('Prefer', 'odata.include-annotations="*"');
xhr.onreadystatechange = function () {
if (this.readyState == 4) {
if (this.status == 200) {
console.log(this.response);
var data = JSON.parse(this.response);
// さらにレコードがある場合に再帰
var cookies = data["@Microsoft.Dynamics.CRM.fetchxmlpagingcookie"];
if (cookies) {
page++;
pagingCookie = getPagingCookie(cookies);
executeFetchXml(apiUrl, fetch, page, count, pagingCookie);
}
} else {
var error = JSON.parse(this.response).error;
Xrm.Utility.alertDialog(error.message, function () { });
}
}
};
xhr.send();
}

function getPagingCookie(pagingCookies) {

var div = document.createElement('div');
div.innerHTML = pagingCookies;
var pageNumber = div.firstChild.attributes.pagenumber.value;
var pagingcookie = div.firstChild.attributes.pagingcookie.value;
pagingcookie = unescape(unescape(pagingcookie));
pagingcookie = pagingcookie.replace(/</g,'&lt;').replace(/>/g,'&gt;');
pagingcookie = pagingcookie.replace(/"/g,''').replace(/'/g,'&'+'quot;');

return "paging-cookie='" + pagingcookie + "'";
}

なかなか厄介でした。。。ページングをするには<fetch>エレメントを変更していく必要があるので、ややこしくなりますね。それでは説明です。

1行目
Web API のURLなので説明は不要ですね。
2行目
取得するページ番号を指定しています。
3行目
取得するレコード数を指定しています。
5行目 ~ 12行目
FetchXMLの<entity>以下を指定しています。
18行目 ~ 24行目
<fetch>エレメントにページングの設定を行っています。
33行目
ページングに使用する『@Microsoft.Dynamics.CRM.fetchxmlpagingcookie』を取得するために注釈の指定が必要です。(ちょっと調べたのですが"*"でなく、単体で取得する注釈がわかりませんでした。。)
41行目 ~ 43行目
さらにレコードがあるかどうかは、戻ってきたデータ『@Microsoft.Dynamics.CRM.fetchxmlpagingcookie』があるかどうかで判定し、再帰で呼び出すためにページ番号、クッキーを再設定しています。
55行目
『getPagingCookie』では『@Microsoft.Dynamics.CRM.fetchxmlpagingcookie』で取得した文字列からpagingcookie属性の値の取得を行っています。『@Microsoft.Dynamics.CRM.fetchxmlpagingcookie』には下記のような文字列が設定されています。

<cookie pagenumber="2" pagingcookie="%253ccookie%2520page%253d%25223%2522%253e%253cincidentid%2520last%253d%2522%257bE384A5B4-498A-E711-8118-C4346BC53068%257d%2522%2520first%253d%2522%257bD184A5B4-498A-E711-8118-C4346BC53068%257d%2522%2520%252f%253e%253c%252fcookie%253e" istracking="False" />

FetchXMLでのページングはこんな感じです。いかがですか?参考になりますでしょうか。私は疲れました(笑)


今回、はじめてFetchXMLでのページングを実装したのですが、『@Microsoft.Dynamics.CRM.fetchxmlpagingcookie』で返される cookie の中に pagenumber があるのでその値をインクリメントすればいいと思ってやっていたんですが・・・正しい値が返ってこず苦戦しました(笑)
このように実装してみないとわからないことがあるのが Dynamics 365 の醍醐味ですね。
次回は・・・・って何も考えてなかったw 何かしら有益な情報をかけるようにネタを探しておきますm(_ _)m

※ 記事の内容は個人発信の参考情報です。記事内容のご利用は、ご自身の判断でお願いします。

この記事を書いた人
原田 研吾

文系プログラマ(.NET Framework、Java)。
25歳から始めたプログラムは死ぬ気で頑張った(誰も褒めてくれないので自分で誉めてます)。
気が付けば製品開発部のマネージャー・・・
弊社Dynamics CRM トレーニングの講師をやったりもします。
事業部やら役職やらありますが、『事業部内の便利屋』が一番フィットする肩書です。
アーカス・ジャパン株式会社 CRM製品
CRM製品に関するお問い合わせ
TEL 06-6195-7501
お問い合わせはこちら

同じカテゴリの記事

Translate »