Paging Cookieの落とし穴
みなさん、こんにちは。
今回は、最近お客様よりご相談を受けることが多くあった他テーブルを結合して5,000件以上のデータ取得を行う際の落とし穴を紹介したいと思います。
発生事象
FetchXmlを使用して5,000件以上の取得にはPagingCookieの利用が推奨されています。
また、親子関係のあるテーブルを結合して取得する際には、link-entityを使用して取得することになりますが、その際に落とし穴があります。
以下のように1つの親レコードに対して子レコードを4つずつ持っているレコードがあるとします。
これらのレコードをページサイズを5にして取得する場合、以下のようなFetchXmlを書いて取得します。
<fetch mapping=”logical” count=”5″ version=”1.0″>
<entity name="親エンティティ名">
<link-entity name="子エンティティ名" from="親エンティティの主キーフィールド名" to="子エンティティの親を参照しているフィールド名">
<attribute name="子エンティティの主キーフィールド名" />
<attribute name="子エンティティのプライマリフィールド名" />
</link-entity>
</entity>
</fetch>
この取得結果は、次のようになります。
そして次のPagingCookieも返されます。
<cookie page="1">
<親エンティティ主キー項目名 last="b91f4114-fa69-44f4-992e-24b2cc49c726" first="70668a69-9ab9-4017-9bcb-4c841ffbd3f5" />
</cookie>
PagingCookieには、プライマリエンティティの最初と最後の値が含まれます。
2ページ目を取得する際にこのPagingCookieを使用し取得する場合、以下のようなFetchXmlを書いて取得します。
<fetch mapping=”logical” count=”5″ page="2" paging-cookie=<cookie page="1">
<親エンティティ主キー項目名 last="b91f4114-fa69-44f4-992e-24b2cc49c726" first="70668a69-9ab9-4017-9bcb-4c841ffbd3f5" />
</cookie> version=”1.0″>
<entity name="親エンティティ名">
<link-entity name="子エンティティ名" from="親エンティティの主キーフィールド名" to="子エンティティの親を参照しているフィールド名">
<attribute name="子エンティティの主キーフィールド名" />
<attribute name="子エンティティのプライマリフィールド名" />
</link-entity>
</entity>
</fetch>
2ページ目の取得結果は、次のようになり、Parent 2のレコードが3件取得できていないことになります。
解決方法案
上記の事象ですが、PagingCookieに保存された情報が親レコードの主キーのみを保持しており、結合した行を一意に識別しているわけではないために発生しています。
そのため、解決方法としては、以下の3案考えられます。
①プライマリエンティティのIDが一意になるようにFetchXmlを書く
プライマリエンティティを例の場合、子エンティティになるようにし、子から親を参照する形でデータ取得するとプライマリエンティティのIDが一意となり、本事象は発生しなくなります。
②Paging Cookieをそもそも使用しない
Paging Cookieを使用しない方法でも5,000件以上のレコードは取得可能ですので、そういった方法を使用するのも一つです。
ただし、FetchXmlでPaging Cookieを使用しない場合、50,000件までしか取得できないなどといった制約もあるので注意が必要です。
③FetchXmlを複数のクエリに分割し、取得結果をメモリ内で結合する
親と子を分けて取得するなどし、メモリ内で結合する方法です。
確実な方法ではありますが、パフォーマンス面などに注意して実装する必要があります。
どの方法をとるかは、データの持ち方、データ件数、取得したい結果の形により異なるかと思いますので、実現したい方法に合わせてご検討いただければと思います。
様々な実装の中でこういった落とし穴にはまることも多々あるかと思いますので、解決に困っている際には、ぜひ、お気軽にお問合せいただければと思います。