
はじめに
SAP BTPと、SAP SuccessFactorsやSAP S/4 HANAを連携する際、WebAPIであるODataで通信し、データを取得することが多くあります。
取得条件に「lastModifiedDateTime」を設定することで、最終編集日時に基づき有効日が設定されたレコードを取得することが出来ます。ただ、SAP SuccessFactorsでは「lastModifiedDateTime」の条件設定の仕方次第で、検索範囲が異なります。
「lastModifiedDateTime」の条件設定方法次第でデータの検索範囲が変わるのはSAP SuccessFactorsのみの特徴のため、調査時や情報共有時には具体的にどういうことなのかイメージするのに、とても時間がかかりました。
本記事では、実際に取得条件に「lastModifiedDateTime」を設定した場合にどのようにデータが取得できるのか、機能概要、具体例を用いて開発時の不具合原因を解説していきます。
発生した事象
前日に登録・更新されたレコードを取得し、番号の連番を付与する処理を開発していました。
その処理の中で、削除されたレコードも処理対象となる事象が発生しました。
事象の詳細
以下のようなデータが登録されているとします。「2024/7/23 00:00:00」に夜間バッチが実行された場合、前日に登録・更新されたNo.1,4,6のレコードに連番を付与する処理で、No.2の前日に削除されたレコードにも連番が付与されていることが判明しました。
No | 対象データ | 処理内容 | 更新日付(lastModifiedDateTime) |
---|---|---|---|
1 | A | 登録 | 2024/7/22 09:00:00 |
2 | B | 削除 | 2024/7/22 09:00:00 |
3 | C | 登録 | 2024/7/20 09:00:00 |
4 | D | 登録 | 2024/7/22 09:00:00 |
5 | E | 更新 | 2024/7/21 09:00:00 |
6 | F | 更新 | 2024/7/22 09:00:00 |
原因
「lastModifiedDateTime >= 【日付】」、または「【日付】<= lastModifiedDateTime」を取得条件に設定した場合、【日付】に設定する値が同じであっても、異なる結果が返されます。
これは、条件式の右辺にリテラル値を持ってくるか、左辺にリテラル値を持ってくるかによって、検索範囲が異なるためです。
lastModifiedDateTime設定時の検索範囲
取得条件に「lastModifiedDateTime >= 【日付】」を設定(右辺にリテラル値を設定)した場合、検索範囲がエンティティレコードと監査ログの両方となります。そのため、取得時点で有効な歴のみではなく、監査ログも対象となります。よって、取得した結果に削除のレコードが含まれることがあります。
一方、取得条件に「【日付】<= lastModifiedDateTime」を設定(左辺にリテラル値を設定)した場合、エンティティレコードのみとなります。そのため、取得時点で有効な歴のみ抽出することが可能です。
取得条件 | 検索範囲 |
---|---|
lastModifiedDateTime ge 【日付】 ※lastModifiedDateTime >= 【日付】 | エンティティレコードと監査ログの両方 |
【日付】 le lastModifiedDateTime ※【日付】<= lastModifiedDateTime | エンティティレコードのみ |
不具合原因
前日分のデータを取得する際に、OData取得リクエスト時の取得条件を、「lastModifiedDateTime >= 【日付】」と設定していたことで、削除したデータについても抽出対象に含まれていました。
そのため、削除データに対しても連番が付与され更新されていました。
https://<hostname>/odata/v2/<エンティティ名>?$filter=lastModifiedDateTime ge datetime'2024-07-22T00:00:00'
対処方法
以下のように、「【日付】<= lastModifiedDateTime」と設定することで、削除データは抽出されなくなり、削除データは連番付与の対象外とすることが出来ました。
https://<hostname>/odata/v2/<エンティティ名>?$filter=datetime'2024-07-22T00:00:00' le lastModifiedDateTime
取得例
実際に「lastModifiedDateTime」を取得条件に設定した際の取得例について、具体例を用意しました。
EmpJobにユーザID:Aのレコードが以下のように登録されてる場合、取得結果については次のようになります。
(取得時点のシステム日付は2024/7/23で想定)
- 登録データ
No | ユーザID | StartDate | EndDate | SeqNumber | lastModifiedDateTime | レコードの状態 |
---|---|---|---|---|---|---|
1 | A | 2024/07/22 | 9999/12/31 | 2 | 2024/07/22T09:00:00 | 削除 |
2 | A | 2024/07/22 | 9999/12/31 | 1 | 2024/07/22T09:00:00 | 登録 |
3 | A | 1900/01/01 | 2024/07/21 | 2 | 2024/07/01T09:00:00 | 登録 |
- 歴管理のイメージ
レコードNo.1は削除状態のため、2024/07/22~はNo.2の歴が有効となります。

※歴管理については、当ブログの別記事である「初心者がつまづきやすいSuccessFactors APIの歴管理を徹底解説!query options(fromDate, toDate, asOfDate, filterParentDate)を使いこなす」をご参照ください。
※fromDate,toDateを指定しない場合は、SAP SuccessFactorsの仕様としてSeqNumberが最大のレコードのみが抽出されます。
取得条件に「lastModifiedDateTime >= 【日付】」設定されている場合
- リクエスト内容
https://<hostname>/odata/v2/EmpJob?$filter=userId eq 'A' and lastModifiedDateTime ge datetime'2024-07-22T00:00:00's
- 取得結果
エンティティレコードと監査ログの両方が取得対象となるため、システム日付時点で有効な歴だけではなく、監査ログのチェックで2024/07/22に変更されたレコード(削除されたレコード)も抽出対象となります。そのため、SeqNumberが最大でかつ、前日に削除されたNo.1のレコードが取得できます。
No | ユーザID | StartDate | EndDate | SeqNumber | lastModifiedDateTime |
---|---|---|---|---|---|
1 | A | 2024/07/22 | 9999/12/31 | 2 | 2024/07/22T09:00:00 |
取得条件に「【日付】<= lastModifiedDateTime」が設定されている場合
- リクエスト内容
https://<hostname>/odata/v2/EmpJob?$filter=userId eq 'A' and datetime'2024-07-22T00:00:00' le lastModifiedDateTime
- 取得結果
エンティティレコードのみが取得対象となるため、システム日付時点で登録されているレコード(有効なレコード)のみが抽出対象となります。そのため、システム日付時点で有効な歴でかつ前日に更新されているNo.2のレコードが取得できます。
No | ユーザID | StartDate | EndDate | SeqNumber | lastModifiedDateTime |
---|---|---|---|---|---|
2 | A | 2017/11/14 | 9999/12/31 | 1 | 2024/07/22T09:00:00 |
取得条件に「lastModifiedDateTime」が設定されていない場合
- リクエスト内容
https://<hostname>/odata/v2/EmpJob?$filter=userId eq 'A'
- 取得結果
取得処理実行時点(システム日付時点)で有効なデータが取得されるため、No.2の歴が取得できます。
No | ユーザID | StartDate | EndDate | SeqNumber | lastModifiedDateTime |
---|---|---|---|---|---|
2 | A | 2017/11/14 | 9999/12/31 | 1 | 2024/07/22T09:00:00 |
※取得時にasOfDate,fromDate,toDateを設定することで、取得対象が変わります。asOfDate,fromDate,toDateを設定した際のデータ取得例についてはQiita 記事にてまとめているのでこちらをご覧ください。
さいごに
「lastModifiedDateTime」の条件設定方法次第でデータの検索範囲が変わることを知らずに、不具合発生時には、調査にすごく手間取りました。また、原因が分かった後も、チームメンバーに不具合原因の説明する際やお客様説明時に、具体例をイメージしづらく情報共有に手間取りました。
開発時に今回と同事象の不具合が発生した際には、こちらのブログを参考にメンバー間の情報共有に役立てていただければと思います。
今後も実際に発生した不具合の事例について、機能概要、原因、対応方法等をまとめて、ブログを執筆していきます。
最後まで閲覧いただきありがとうございました。
投稿者プロフィール

-
BS事業部 BSグループの樋口です。
SAP BTP(Business Technology Platform)とSAP Fioriを活用した開発案件に携わっています。