送信履歴テーブルNULL値対応実装手順書.md

# 送信履歴テーブルNULL値対応実装手順書

## 概要
送信履歴テーブルからデータを取得する際に、特定のカラムがNULLである可能性を考慮した処理を実装します。これにより、送信パターンを使用しない場合などでもエラーが発生せずにデータを取得できるようになります。

## 対象カラムとNULL値の可能性

### NULL値を許可するカラム
1. **送信パターンID** (`int?`)
   - 送信パターンを使用しない場合はNULL
2. **送信パターン名称** (`nvarchar(100)`)
   - 送信パターンを使用しない場合はNULL
3. **送信パターン定型文** (`nvarchar(max)`)
   - 送信パターンを使用しない場合はNULL
4. **送信パターン送信対象** (`int?`)
   - 送信パターンを使用しない場合はNULL
5. **送信パターン並び順** (`int?`)
   - 送信パターンを使用しない場合はNULL

## 現状の問題点

### SendHistoryDao.cs - GetSendTypeListメソッド (17-69行目)
現在の実装では、`row.Field<T>()`メソッドを使用していますが、int型のカラムに対してNULL値が存在する場合、例外が発生する可能性があります。

```csharp
PatternId = row.Field<int>("送信パターンID"),  // NULL値の場合、例外発生
PatternSortOrder = row.Field<int>("送信パターン並び順"),  // NULL値の場合、例外発生
```

### SendHistoryDao.cs - GetSendHistoryメソッド (71-118行目)
このメソッドでは既にNULL値の考慮がされていますが、一部の処理が統一されていません。

## 実装手順

### ステップ1: GetSendTypeListメソッドの修正

#### 1.1 NULL値を考慮した実装に変更

```csharp
public List<SendHistoryDto> GetSendTypeList(int type)
{
    string sql = $@"
    SELECT 
      *,
    CASE 
        WHEN 送信失敗件数 > 0 
        THEN 'エラーあり'
        ELSE '成功'
    END AS '送信結果'
    FROM dbo.送信履歴
    WHERE 送信タイプ = @type   
    ORDER BY 送信日時 DESC";

    var param = new Dictionary<string, object>
    {
        {"@type",type }
        ,
    };

    DataTable dt = _db.ExecQuery(sql,param);

    var list = new List<SendHistoryDto>();

    foreach (DataRow row in dt.Rows)
    {
        var dto = new SendHistoryDto
        {
            SendHistoryId = row.Field<int>("送信履歴ID"),
            SendType = row.Field<int>("送信タイプ"),
            SuccessCount = row.Field<int>("送信成功件数"),
            FailureCount = row.Field<int>("送信失敗件数"),
            SenderApiToken = row.Field<string>("C_APIトークン"),
            // NULL値を考慮した実装に変更
            PatternId = row["送信パターンID"] != DBNull.Value 
                        ? (int?)Convert.ToInt32(row["送信パターンID"]) 
                        : null,
            PatternName = row.Field<string>("送信パターン名称"),
            PatternTemplateText = row.Field<string>("送信パターン定型文"),
            PatternTarget = row["送信パターン送信対象"] != DBNull.Value 
                           ? (int?)Convert.ToInt32(row["送信パターン送信対象"]) 
                           : null,
            PatternSortOrder = row["送信パターン並び順"] != DBNull.Value 
                              ? (int?)Convert.ToInt32(row["送信パターン並び順"]) 
                              : null,
            SendContents = row.Field<string>("送信内容"),
            RegularDestinationSelectType = (Constants.DESTINAION_SELECT_TYPE)Convert.ToInt32(row["定期送信_送信対象"]),
            RegularFolderPath = row.Field<string>("定期送信_添付ファイル管理フォルダパス"),
            AdhocHasAttachment = row.Field<bool>("不定期送信_添付ファイル有無"),
            AdhocAttachmentFilePath = row.Field<string>("不定期送信_添付ファイルパス"),
            SendDt = row.Field<DateTime?>("送信日時"),
            SendResults = row.Field<string>("送信結果")
           ,
        };

        list.Add(dto);
    }

    return list;
}
```

### ステップ2: GetSendHistoryメソッドの確認と統一

#### 2.1 現在の実装を確認
GetSendHistoryメソッドは既にNULL値の考慮がされているため、大きな修正は不要です。ただし、コードの一貫性を保つため、以下の点を確認します:

1. すべてのNullable型カラムに対してDBNull.Valueのチェックが行われている
2. 文字列型のカラムに対しては`as string`を使用している
3. 数値型のNullableカラムに対しては適切な変換が行われている

### ステップ3: DTOクラスの確認

#### 3.1 SendHistoryDto.csの確認
DTOクラスでは既に適切なNullable型が定義されています:

```csharp
public int? PatternId { get; set; }
public int? PatternTarget { get; set; }
public int? PatternSortOrder { get; set; }
```

これらの定義は正しいため、変更は不要です。

### ステップ4: 関連する画面の動作確認

#### 4.1 影響を受ける画面
1. **送信履歴一覧画面** - GetSendTypeListメソッドを使用
2. **送信履歴詳細画面** - GetSendHistoryメソッドを使用
3. **送信失敗データ再送機能** - GetSendHistoryメソッドを使用

#### 4.2 NULL値の表示方法
- **PatternName**がNULLの場合:`"<パターン未指定>"`と表示(MessageSendResultControl.cs 89行目で既に実装済み)
- **その他のNULL値**:適切なデフォルト値または空文字列として表示

## テストシナリオ

### シナリオ1: 送信パターンを使用した送信履歴
1. 送信パターンを選択して送信を実行
2. 送信履歴一覧画面でデータが正しく表示されることを確認
3. 詳細画面でパターン情報が正しく表示されることを確認

### シナリオ2: 送信パターンを使用しない送信履歴
1. 送信パターンを選択せずに送信を実行
2. 送信履歴一覧画面でデータが正しく表示されることを確認
3. 詳細画面でパターン名が`"<パターン未指定>"`と表示されることを確認

### シナリオ3: NULL値を含むデータの再送
1. 送信パターンを使用しない送信で失敗データを作成
2. 送信履歴詳細画面から再送ボタンをクリック
3. エラーが発生せずに再送画面が開くことを確認

## エラーハンドリング

### 想定されるエラー
1. **InvalidCastException** - NULL値をint型にキャストしようとした場合
2. **NullReferenceException** - NULL値に対してメソッドを呼び出した場合

### 対処方法
1. すべてのNullableカラムに対してDBNull.Valueのチェックを実施
2. 適切な型変換とデフォルト値の設定
3. エラーログの記録と適切なエラーメッセージの表示

## 実装の注意点

### 1. パフォーマンスへの配慮
- `row.Field<T>()`メソッドは内部でNULLチェックを行うため、文字列型には引き続き使用
- int型のNullableカラムのみ明示的なNULLチェックを実施

### 2. 既存機能への影響
- GetSendTypeListメソッドを使用している箇所の動作確認が必要
- 特に送信履歴一覧画面(SendHistoryDgvControl)での表示を確認

### 3. データベーススキーマとの整合性
- データベースのカラム定義がNULL許可になっていることを確認
- 将来的なスキーマ変更に備えて、柔軟な実装を心がける

## 実装チェックリスト

- [ ] GetSendTypeListメソッドのNULL値対応実装
- [ ] 修正後のコンパイルエラーがないことを確認
- [ ] 送信履歴一覧画面での表示確認
- [ ] 送信履歴詳細画面での表示確認
- [ ] NULL値を含むデータでの再送機能の動作確認
- [ ] 単体テストの実施(NULL値を含むテストケース)
- [ ] 結合テストの実施
- [ ] コードレビューの実施

## 追加の推奨事項

### 1. 単体テストの作成
NULL値を含むテストデータを使用した単体テストを作成することを推奨します。

### 2. ログ出力の追加
NULL値が検出された場合のデバッグログを追加することで、問題の早期発見が可能になります。

### 3. 定数の定義
デフォルト値や表示文字列(例:`"<パターン未指定>"`)を定数として定義することで、保守性が向上します。

## まとめ

この実装により、送信履歴テーブルのNULL値を含むデータを安全に取得・表示できるようになります。特に送信パターンを使用しない送信の履歴も正しく扱えるようになり、システムの柔軟性が向上します。