歴管理のあるエンティティの取得と最終更新日でFilterするときの注意点

## はじめに
バッチ処理の開発時に、前日に更新されたレコードを使用し、夜間バッチで関連データを作成するという処理を作成する中で、「lastModifiedDateTime」のFilter条件の配置や「asOfDate」「fromDate」「toDate」パラメータの設定内容で取得結果が異なりました。
そのため、開発時に確認した結果を備忘録的にまとめておきたいと思います。

## asOfDate,fromDate,toDateパラメータとの関連
歴管理のあるエンティティについては自動でasOfDateが適用され、fromDate,toDateを設定することで取得対象の範囲を変更することが出来ます。

#### asOfDate,fromDate,toDateパラメータを設定していない場合
asOfDate=システム日付が自動で適用され、クエリ実行時点で有効な歴を取得します。

#### asOfDate=2024-01-01を設定している場合
2024/1/1時点で有効な歴を取得します。

#### fromDate=1900-01-01&toDate=システム日付を設定した場合
1900/1/1以降でかつシステム日付までで有効な歴がすべて取得できます。

#### fromDate=システム日付&toDate=9999-12-31を設定した場合
 システム日付以降で有効な歴が取得できます（これから有効になる歴等もtoDateを設定することで取得することが可能です。

## lastModifiedDateTimeを右に配置するか、左に配置するか
lastModifiedDateTimeの動作は、lastModifiedDateTimeパラメータを左に配置するか、右に配置するかによって異なります。
以下の2つの取得条件について、基準が同じであっても、異なる結果を返却することがあります。

- lastModifiedDateTimeパラメータを左に配置した場合
```
$filter=lastModifiedDateTime ge datetime'2018-03-01T00:00:00'
```

- lastModifiedDateTimeパラメータを右に配置した場合
```
$filter=datetime'2018-03-01T00:00:00' le lastModifiedDateTime
```


取得結果が異なる理由として検索範囲が以下のように異なることから取得結果が異なります。

| lastModifiedDateTimeの位置| 検索範囲 |
|:-----------------|:-----------------|
| 左| エンティティレコードと監査ログの両方 |
| 右| エンティティレコードのみ |

## 取得例
EmpJobに以下のようなレコードが登録されてる場合の取得例についてまとめます。

| No| ユーザID |StartDate|EndDate|SeqNumber|lastModifiedDateTime|
|:--------:|:--------:|:--------:|:-------------|:--------|:--------:|
| 1| ユーザA |2017/11/14|9999/12/31|1|2018/02/06T05:17:20|
| 2| ユーザA |2017/11/02|2017/11/13|2|2017/11/03T04:40:27|
| 3| ユーザA |2017/11/02|2017/11/02|1|2017/11/03T03:32:06|
| 4| ユーザA |1900/01/01|2017/11/01|1|2011/10/11T09:44:56|

### 例１　lastModifiedDateTime設定なし
- リクエスト内容
```
https://<hostname>/odata/v2/EmpJob?$filter=userId eq 'ユーザA'
```

- 取得結果
「asOfDate」「fromDate」「toDate」パラメータを設定しない場合には、asOfDate = システム日付がデフォルトで設定されてるため、システム日付時点に有効な歴のみが取得できます。

| No| ユーザID |StartDate|EndDate|SeqNumber|lastModifiedDateTime|
|:--------:|:--------:|:--------:|:-------------|:--------|:--------:|
| 1| ユーザA |2017/11/14|9999/12/31|1|2018/02/06T05:17:20 |

### 例2　lastModifiedDateTimeが左の場合
- リクエスト内容
```
https://<hostname>/odata/v2/EmpJob?$filter=userId eq 'ユーザA' and 
lastModifiedDateTime gt datetimeoffset'2011-01-01T00:00:00Z'
```

- 取得結果
「asOfDate」「fromDate」「toDate」パラメータを設定しない場合には、asOfDate = システム日付がデフォルトで設定されてるため、システム日付時点に有効な歴、かつ2011/01/01以降に変更のあったレコードが取得できます。

| No| ユーザID |StartDate|EndDate|SeqNumber|lastModifiedDateTime|
|:--------:|:--------:|:--------:|:------------:|:--------|:--------:|
| 1| ユーザA |2017/11/14|9999/12/31|1|2018/02/06T05:17:20|

### 例3　lastModifiedDateTimeが左、fromDateを設定した場合
- リクエスト内容
```
https://<hostname>/odata/v2/EmpJob?$filter=userId eq 'ユーザA' and 
lastModifiedDateTime gt datetimeoffset'2011-01-01T00:00:00Z'&fromDate=1990-01-01
```

- 取得結果
「fromDate」パラメータを設定しているため、1900/1/1以降有効、かつ2011/01/01以降に変更のあったレコードが取得できます。

| No| ユーザID |StartDate|EndDate|SeqNumber|lastModifiedDateTime|
|:--------:|:--------:|:--------:|:------------:|:--------|:--------:|
| 1| ユーザA |2017/11/14|9999/12/31|1|2018/02/06T05:17:20|
| 2| ユーザA |2017/11/02|2017/11/13|2|2017/11/03T04:40:27|
| 3| ユーザA |2017/11/02|2017/11/02|1|2017/11/03T03:32:06|
| 4| ユーザA |1900/01/01|2017/11/01|1|2011/10/11T09:44:56|

### 例4　2024/6/20にレコード1を削除後に、lastModifiedDateTimeを左に設定した場合

- 削除後の状態
StartDateが「2017/11/14」EndDateが「9999/12/31」の歴が削除され、StartDate「2017/11/02」SeqNumber「2」の歴が有効となり、EndDate「9999/12/31」に変更されています。

| No| ユーザID |StartDate|EndDate|SeqNumber|lastModifiedDateTime|
|:--------:|:--------:|:--------:|:-------------|:--------|:--------:|
| 2| ユーザA |2017/11/02|9999/12/31|2|2017/11/03T04:40:27|
| 3| ユーザA |2017/11/02|2017/11/02|1|2017/11/03T03:32:06|
| 4| ユーザA |1900/01/01|2017/11/01|1|2011/10/11T09:44:56|


- リクエスト内容
```
https://<hostname>/odata/v2/EmpJob?$filter=userId eq 'ユーザA' and 
lastModifiedDateTime gt datetimeoffset'2024-06-20T00:00:00Z'
```

- 取得結果
「asOfDate」「fromDate」「toDate」パラメータを設定しない場合には、asOfDate = システム日付がデフォルトで設定されてるため、システム日付時点に有効な歴でかつ、2024/06/20以降に変更されたレコードを取得時にはエンティティレコードに対象データが存在しませんが、監査ログのチェックで2024/06/20以降に変更されたレコード（削除されたレコード）が取得結果に反映されます。


| No| ユーザID |StartDate|EndDate|SeqNumber|lastModifiedDateTime|
|:--------:|:--------:|:--------:|:------------:|:--------|:--------:|
| 1| ユーザA |2017/11/14|9999/12/31|1|2018/06/20T00:00:00|


### 例5　2024/6/20にレコード1を削除後に、lastModifiedDateTimeを右に設定した場合

- 削除後の状態
例4の削除後の状態と同様にStartDateが「2017/11/14」EndDateが「9999/12/31」の歴が削除され、StartDate「2017/11/02」SeqNumber「2」の歴が有効となり、EndDate「9999/12/31」に変更されています。

| No| ユーザID |StartDate|EndDate|SeqNumber|lastModifiedDateTime|
|:--------:|:--------:|:--------:|:-------------|:--------|:--------:|
| 2| ユーザA |2017/11/02|9999/12/31|2|2017/11/03T04:40:27|
| 3| ユーザA |2017/11/02|2017/11/02|1|2017/11/03T03:32:06|
| 4| ユーザA |1900/01/01|2017/11/01|1|2011/10/11T09:44:56|

- リクエスト内容
```
https://<hostname>/odata/v2/EmpJob?$filter=userId eq 'ユーザA' and 
datetimeoffset'2024-06-20T00:00:00Z' le lastModifiedDateTime
```

- 取得結果
2024/06/20以降に変更されたレコードはエンティティレコードに存在しないため、レコードは取得されません。


| No| ユーザID |StartDate|EndDate|SeqNumber|lastModifiedDateTime|
|:--------:|:--------:|:--------:|:------------:|:--------|:--------:|

## さいごに
「lastModifiedDateTime」のFilter条件の配置や「asOfDate」「fromDate」「toDate」パラメータ以外にもデータ取得時に、想定と違う結果が取得され、調査をしたことがあるので、開発時に詰まった内容等については、今後備忘録として掲載しようと思います。