# 検索機能完全実装手順書
## 概要
本手順書は、ChatworkBulkSenderアプリケーションの顧客マスタ、送信パターンマスタ、送信履歴の検索機能の完全な実装手順を記載したものです。
未実装機能の追加、先頭ゼロ自動削除機能、日付初期値の修正を含む包括的な実装ガイドです。
## 実装する機能一覧
1. 送信履歴画面の管理番号検索機能(未実装)
2. 送信履歴画面の顧客名検索機能(未実装)
3. 全画面の管理番号入力時の先頭ゼロ自動削除機能
4. 送信履歴画面の日付初期値修正
5. 送信履歴画面の初期表示設定確認
## 対象ファイル一覧
1. `ChatworkBulkSender\Daos\SendHistoryDetailDao.cs`
2. `ChatworkBulkSender\UserControls\SendHistoryDgvControl.cs`
3. `ChatworkBulkSender\UserControls\SearchBoxControl.cs`
4. `ChatworkBulkSender\UserControls\PatternSearchBoxControl.cs`
5. `ChatworkBulkSender\UserControls\HistorySearchBoxControl.cs`
6. `ChatworkBulkSender\UserControls\HistorySearchBoxControl.Designer.cs`
---
## 1. SendHistoryDetailDao.cs の修正
### ファイルパス
`ChatworkBulkSender\Daos\SendHistoryDetailDao.cs`
### 修正箇所:ファイル末尾に検索メソッドを追加(103行目の後)
#### 追加するコード:
```csharp
/// <summary>
/// 管理番号で検索して該当する送信履歴IDのリストを取得
/// </summary>
/// <param name="managementNumber">管理番号(前方一致)</param>
/// <returns>送信履歴IDのリスト</returns>
public List<int> GetSendHistoryIdsByManagementNumber(string managementNumber)
{
if (string.IsNullOrWhiteSpace(managementNumber))
return new List<int>();
// 先頭のゼロを削除して数値に変換
if (int.TryParse(managementNumber, out int mgmtNumber))
{
managementNumber = mgmtNumber.ToString();
}
const string sql = @"
SELECT DISTINCT 送信履歴ID
FROM dbo.送信履歴_詳細
WHERE CAST(管理番号 AS VARCHAR) LIKE @ManagementNumber + '%'
ORDER BY 送信履歴ID DESC";
var param = new Dictionary<string, object>
{
{ "@ManagementNumber", managementNumber }
};
DataTable dt = _db.ExecQuery(sql, param);
var list = new List<int>();
foreach (DataRow row in dt.Rows)
{
list.Add(Convert.ToInt32(row["送信履歴ID"]));
}
return list;
}
/// <summary>
/// 顧客名で検索して該当する送信履歴IDのリストを取得
/// </summary>
/// <param name="customerName">顧客名(部分一致)</param>
/// <returns>送信履歴IDのリスト</returns>
public List<int> GetSendHistoryIdsByCustomerName(string customerName)
{
if (string.IsNullOrWhiteSpace(customerName))
return new List<int>();
const string sql = @"
SELECT DISTINCT 送信履歴ID
FROM dbo.送信履歴_詳細
WHERE 顧客名 LIKE '%' + @CustomerName + '%'
ORDER BY 送信履歴ID DESC";
var param = new Dictionary<string, object>
{
{ "@CustomerName", customerName }
};
DataTable dt = _db.ExecQuery(sql, param);
var list = new List<int>();
foreach (DataRow row in dt.Rows)
{
list.Add(Convert.ToInt32(row["送信履歴ID"]));
}
return list;
}
```
### 修正理由
送信履歴画面で管理番号と顧客名による検索が未実装だったため、送信履歴詳細テーブルから該当データを検索するメソッドを追加。
---
## 2. SendHistoryDgvControl.cs の修正
### ファイルパス
`ChatworkBulkSender\UserControls\SendHistoryDgvControl.cs`
### 修正箇所1:usingディレクティブの確認(4行目)
```csharp
using System.Linq; // 既に存在することを確認
```
### 修正箇所2:Search メソッドの修正(212-253行目)
#### 修正前のコード:
```csharp
// 管理番号でフィルタ
if (criteria.ContainsKey("ManagementNumber") && !string.IsNullOrWhiteSpace(criteria["ManagementNumber"].ToString()))
{
string mgmtNumber = criteria["ManagementNumber"].ToString();
// 送信履歴詳細から管理番号で検索する必要があるため、今回は簡易的にスキップ
// TODO: 詳細検索の実装が必要な場合は、SendHistoryDetailDaoから検索する
}
// パターン名称でフィルタ
if (criteria.ContainsKey("PatternName") && !string.IsNullOrWhiteSpace(criteria["PatternName"].ToString()))
{
string patternName = criteria["PatternName"].ToString();
filteredList = filteredList.Where(h => h.PatternName != null && h.PatternName.Contains(patternName));
}
// 顧客名でフィルタ
if (criteria.ContainsKey("CustomerName") && !string.IsNullOrWhiteSpace(criteria["CustomerName"].ToString()))
{
string customerName = criteria["CustomerName"].ToString();
// 送信履歴詳細から顧客名で検索する必要があるため、今回は簡易的にスキップ
// TODO: 詳細検索の実装が必要な場合は、SendHistoryDetailDaoから検索する
}
```
#### 修正後のコード:
```csharp
// 管理番号でフィルタ
if (criteria.ContainsKey("ManagementNumber") && !string.IsNullOrWhiteSpace(criteria["ManagementNumber"].ToString()))
{
string mgmtNumber = criteria["ManagementNumber"].ToString();
var detailDao = new SendHistoryDetailDao();
var matchingHistoryIds = detailDao.GetSendHistoryIdsByManagementNumber(mgmtNumber);
if (matchingHistoryIds.Any())
{
filteredList = filteredList.Where(h => matchingHistoryIds.Contains(h.SendHistoryId));
}
else
{
// 該当なしの場合は空のリストにする
filteredList = new List<SendHistoryDto>().AsEnumerable();
}
}
// パターン名称でフィルタ
if (criteria.ContainsKey("PatternName") && !string.IsNullOrWhiteSpace(criteria["PatternName"].ToString()))
{
string patternName = criteria["PatternName"].ToString();
filteredList = filteredList.Where(h => h.PatternName != null && h.PatternName.Contains(patternName));
}
// 顧客名でフィルタ
if (criteria.ContainsKey("CustomerName") && !string.IsNullOrWhiteSpace(criteria["CustomerName"].ToString()))
{
string customerName = criteria["CustomerName"].ToString();
var detailDao = new SendHistoryDetailDao();
var matchingHistoryIds = detailDao.GetSendHistoryIdsByCustomerName(customerName);
if (matchingHistoryIds.Any())
{
filteredList = filteredList.Where(h => matchingHistoryIds.Contains(h.SendHistoryId));
}
else
{
// 該当なしの場合は空のリストにする
filteredList = new List<SendHistoryDto>().AsEnumerable();
}
}
```
### 修正理由
TODOコメントで残されていた管理番号と顧客名の検索機能を実装。SendHistoryDetailDaoの新しいメソッドを呼び出して検索を実行。
---
## 3. SearchBoxControl.cs の修正(顧客マスタ用)
### ファイルパス
`ChatworkBulkSender\UserControls\SearchBoxControl.cs`
### 修正箇所:MgmtNumberTxtBox_TextChanged メソッド(141-180行目)
#### 修正前のコード:
```csharp
/// <summary>
/// 管理番号テキストボックスのTextChangedイベントハンドラ
/// </summary>
private void MgmtNumberTxtBox_TextChanged(object sender, EventArgs e)
{
// 貼り付けられた場合のチェック
if (!string.IsNullOrWhiteSpace(mgmtNumberTxtBox.Text))
{
if (!ValidationHelperUtil.IsValidManagementNumber(mgmtNumberTxtBox.Text))
{
// 背景色を薄い赤にして視覚的にエラーを示す
mgmtNumberTxtBox.BackColor = Color.FromArgb(255, 230, 230);
errorToolTip.Show(ValidationHelperUtil.GetManagementNumberFormatErrorMessage(),
mgmtNumberTxtBox, 0, -25, 3000);
}
else
{
// 正常な場合は背景色を元に戻す
mgmtNumberTxtBox.BackColor = SystemColors.Window;
errorToolTip.Hide(mgmtNumberTxtBox);
}
}
else
{
// 空の場合も背景色を元に戻す
mgmtNumberTxtBox.BackColor = SystemColors.Window;
errorToolTip.Hide(mgmtNumberTxtBox);
}
}
```
#### 修正後のコード:
```csharp
/// <summary>
/// 管理番号テキストボックスのTextChangedイベントハンドラ
/// </summary>
private void MgmtNumberTxtBox_TextChanged(object sender, EventArgs e)
{
// 先頭のゼロを削除する処理
if (!string.IsNullOrWhiteSpace(mgmtNumberTxtBox.Text))
{
string text = mgmtNumberTxtBox.Text;
// 先頭の0を削除(001 → 1)
if (text.Length > 1 && text.StartsWith("0"))
{
if (int.TryParse(text, out int number))
{
mgmtNumberTxtBox.Text = number.ToString();
// カーソルを末尾に移動
mgmtNumberTxtBox.SelectionStart = mgmtNumberTxtBox.Text.Length;
}
}
// バリデーション
if (!ValidationHelperUtil.IsValidManagementNumber(mgmtNumberTxtBox.Text))
{
// 背景色を薄い赤にして視覚的にエラーを示す
mgmtNumberTxtBox.BackColor = Color.FromArgb(255, 230, 230);
errorToolTip.Show(ValidationHelperUtil.GetManagementNumberFormatErrorMessage(),
mgmtNumberTxtBox, 0, -25, 3000);
}
else
{
// 正常な場合は背景色を元に戻す
mgmtNumberTxtBox.BackColor = SystemColors.Window;
errorToolTip.Hide(mgmtNumberTxtBox);
}
}
else
{
// 空の場合も背景色を元に戻す
mgmtNumberTxtBox.BackColor = SystemColors.Window;
errorToolTip.Hide(mgmtNumberTxtBox);
}
}
```
### 修正理由
管理番号入力時に「001」のような先頭ゼロ付きの数値が入力された場合、自動的に「1」に変換する機能を追加。
---
## 4. PatternSearchBoxControl.cs の修正(送信パターンマスタ用)
### ファイルパス
`ChatworkBulkSender\UserControls\PatternSearchBoxControl.cs`
### 修正箇所:MgmtNumberTxtBox_TextChanged メソッド(125-164行目)
#### 修正前のコード:
```csharp
/// <summary>
/// パターンIDテキストボックスのTextChangedイベントハンドラ
/// </summary>
private void MgmtNumberTxtBox_TextChanged(object sender, EventArgs e)
{
// 貼り付けられた場合のチェック
if (!string.IsNullOrWhiteSpace(mgmtNumberTxtBox.Text))
{
if (!ValidationHelperUtil.IsValidManagementNumber(mgmtNumberTxtBox.Text))
{
// 背景色を薄い赤にして視覚的にエラーを示す
mgmtNumberTxtBox.BackColor = Color.FromArgb(255, 230, 230);
errorToolTip.Show("パターンIDは1以上の半角数字で入力してください。",
mgmtNumberTxtBox, 0, -25, 3000);
}
else
{
// 正常な場合は背景色を元に戻す
mgmtNumberTxtBox.BackColor = SystemColors.Window;
errorToolTip.Hide(mgmtNumberTxtBox);
}
}
else
{
// 空の場合も背景色を元に戻す
mgmtNumberTxtBox.BackColor = SystemColors.Window;
errorToolTip.Hide(mgmtNumberTxtBox);
}
}
```
#### 修正後のコード:
```csharp
/// <summary>
/// パターンIDテキストボックスのTextChangedイベントハンドラ
/// </summary>
private void MgmtNumberTxtBox_TextChanged(object sender, EventArgs e)
{
// 先頭のゼロを削除する処理
if (!string.IsNullOrWhiteSpace(mgmtNumberTxtBox.Text))
{
string text = mgmtNumberTxtBox.Text;
// 先頭の0を削除(001 → 1)
if (text.Length > 1 && text.StartsWith("0"))
{
if (int.TryParse(text, out int number))
{
mgmtNumberTxtBox.Text = number.ToString();
// カーソルを末尾に移動
mgmtNumberTxtBox.SelectionStart = mgmtNumberTxtBox.Text.Length;
}
}
// バリデーション
if (!ValidationHelperUtil.IsValidManagementNumber(mgmtNumberTxtBox.Text))
{
// 背景色を薄い赤にして視覚的にエラーを示す
mgmtNumberTxtBox.BackColor = Color.FromArgb(255, 230, 230);
errorToolTip.Show("パターンIDは1以上の半角数字で入力してください。",
mgmtNumberTxtBox, 0, -25, 3000);
}
else
{
// 正常な場合は背景色を元に戻す
mgmtNumberTxtBox.BackColor = SystemColors.Window;
errorToolTip.Hide(mgmtNumberTxtBox);
}
}
else
{
// 空の場合も背景色を元に戻す
mgmtNumberTxtBox.BackColor = SystemColors.Window;
errorToolTip.Hide(mgmtNumberTxtBox);
}
}
```
### 修正理由
パターンID入力時の先頭ゼロ自動削除機能を追加。
---
## 5. HistorySearchBoxControl.cs の修正(送信履歴用)
### ファイルパス
`ChatworkBulkSender\UserControls\HistorySearchBoxControl.cs`
### 修正箇所1:コンストラクタ(27-41行目)
#### 確認事項:
```csharp
public HistorySearchBoxControl()
{
InitializeComponent();
_pnlSearchCurrentX = panelSearchBox.Width;
// デフォルト表示は空文字
dateTimePickerStart.CustomFormat = " ";
dateTimePickerEnd.CustomFormat = " ";
rdoScheduleSendSelection.Checked = true; // 初期状態で定期送信を選択
// 以下、イベントハンドラの設定が続く...
}
```
### 修正箇所2:MgmtNumberTxtBox_TextChanged メソッド(194-233行目)
#### 修正前のコード:
```csharp
/// <summary>
/// 管理番号テキストボックスのTextChangedイベントハンドラ
/// </summary>
private void MgmtNumberTxtBox_TextChanged(object sender, EventArgs e)
{
// 貼り付けられた場合のチェック
if (!string.IsNullOrWhiteSpace(mgmtNumberTxtBox.Text))
{
if (!ValidationHelperUtil.IsValidManagementNumber(mgmtNumberTxtBox.Text))
{
// 背景色を薄い赤にして視覚的にエラーを示す
mgmtNumberTxtBox.BackColor = Color.FromArgb(255, 230, 230);
errorToolTip.Show(ValidationHelperUtil.GetManagementNumberFormatErrorMessage(),
mgmtNumberTxtBox, 0, -25, 3000);
}
else
{
// 正常な場合は背景色を元に戻す
mgmtNumberTxtBox.BackColor = SystemColors.Window;
errorToolTip.Hide(mgmtNumberTxtBox);
}
}
else
{
// 空の場合も背景色を元に戻す
mgmtNumberTxtBox.BackColor = SystemColors.Window;
errorToolTip.Hide(mgmtNumberTxtBox);
}
}
```
#### 修正後のコード:
```csharp
/// <summary>
/// 管理番号テキストボックスのTextChangedイベントハンドラ
/// </summary>
private void MgmtNumberTxtBox_TextChanged(object sender, EventArgs e)
{
// 先頭のゼロを削除する処理
if (!string.IsNullOrWhiteSpace(mgmtNumberTxtBox.Text))
{
string text = mgmtNumberTxtBox.Text;
// 先頭の0を削除(001 → 1)
if (text.Length > 1 && text.StartsWith("0"))
{
if (int.TryParse(text, out int number))
{
mgmtNumberTxtBox.Text = number.ToString();
// カーソルを末尾に移動
mgmtNumberTxtBox.SelectionStart = mgmtNumberTxtBox.Text.Length;
}
}
// バリデーション
if (!ValidationHelperUtil.IsValidManagementNumber(mgmtNumberTxtBox.Text))
{
// 背景色を薄い赤にして視覚的にエラーを示す
mgmtNumberTxtBox.BackColor = Color.FromArgb(255, 230, 230);
errorToolTip.Show(ValidationHelperUtil.GetManagementNumberFormatErrorMessage(),
mgmtNumberTxtBox, 0, -25, 3000);
}
else
{
// 正常な場合は背景色を元に戻す
mgmtNumberTxtBox.BackColor = SystemColors.Window;
errorToolTip.Hide(mgmtNumberTxtBox);
}
}
else
{
// 空の場合も背景色を元に戻す
mgmtNumberTxtBox.BackColor = SystemColors.Window;
errorToolTip.Hide(mgmtNumberTxtBox);
}
}
```
### 修正理由
送信履歴画面の管理番号入力でも先頭ゼロ自動削除機能を追加。
---
## 6. HistorySearchBoxControl.Designer.cs の修正
### ファイルパス
`ChatworkBulkSender\UserControls\HistorySearchBoxControl.Designer.cs`
### 修正箇所:dateTimePickerEnd の初期値設定(128行目)
#### 修正前のコード:
```csharp
this.dateTimePickerEnd.Name = "dateTimePickerEnd";
this.dateTimePickerEnd.Size = new System.Drawing.Size(225, 28);
this.dateTimePickerEnd.TabIndex = 17;
this.dateTimePickerEnd.Value = new System.DateTime(2025, 7, 16, 0, 0, 0, 0);
this.dateTimePickerEnd.ValueChanged += new System.EventHandler(this.dateTimePickerEnd_ValueChanged);
```
#### 修正後のコード:
```csharp
this.dateTimePickerEnd.Name = "dateTimePickerEnd";
this.dateTimePickerEnd.Size = new System.Drawing.Size(225, 28);
this.dateTimePickerEnd.TabIndex = 17;
this.dateTimePickerEnd.ValueChanged += new System.EventHandler(this.dateTimePickerEnd_ValueChanged);
```
### 修正理由
固定日付(2025年7月16日)が設定されていたため削除。これにより、DateTimePickerのデフォルト値(現在の日時)が使用される。
### 注意事項
Designer.csファイルはVisual Studioのフォームデザイナーで再生成される可能性があるため、恒久的な修正にはフォームデザイナーでの設定変更が推奨される。
---
## テスト手順
### 1. 顧客マスタの検索機能テスト
#### 1.1 管理番号検索(先頭ゼロ削除)
1. 顧客マスタ画面を開く
2. 管理番号に「001」と入力
3. 自動的に「1」に変換されることを確認
4. 検索ボタンをクリック
5. 管理番号1番のデータが表示されることを確認
#### 1.2 顧客名検索
1. 顧客名に部分文字列を入力
2. 検索ボタンをクリック
3. 該当する顧客データが表示されることを確認
### 2. 送信パターンマスタの検索機能テスト
#### 2.1 パターンID検索(先頭ゼロ削除)
1. 送信パターンマスタ画面を開く
2. パターンIDに「002」と入力
3. 自動的に「2」に変換されることを確認
4. 検索ボタンをクリック
5. パターンID2番のデータが表示されることを確認
#### 2.2 関連顧客検索
1. 管理番号または顧客名を入力
2. 検索ボタンをクリック
3. 該当する顧客が紐づいているパターンが表示されることを確認
### 3. 送信履歴の検索機能テスト
#### 3.1 管理番号検索(新規実装)
1. 送信履歴画面を開く
2. 管理番号に「003」と入力
3. 自動的に「3」に変換されることを確認
4. 検索ボタンをクリック
5. 管理番号3番の顧客への送信履歴が表示されることを確認
#### 3.2 顧客名検索(新規実装)
1. 顧客名に部分文字列を入力
2. 検索ボタンをクリック
3. 該当する顧客への送信履歴が表示されることを確認
#### 3.3 日付範囲検索
1. 開始日と終了日を選択
2. 終了日のカレンダーが現在日付周辺で開くことを確認(過去の固定日付でないこと)
3. 検索ボタンをクリック
4. 指定期間の送信履歴が表示されることを確認
#### 3.4 初期表示確認
1. 送信履歴画面を開く
2. 「定期送信」ラジオボタンが選択されていることを確認
3. DataGridViewに定期送信のデータが表示されることを確認
---
## 実装チェックリスト
### DAOレベル
- [ ] SendHistoryDetailDao.cs - GetSendHistoryIdsByManagementNumberメソッドの追加
- [ ] SendHistoryDetailDao.cs - GetSendHistoryIdsByCustomerNameメソッドの追加
### ビジネスロジックレベル
- [ ] SendHistoryDgvControl.cs - 管理番号検索の実装
- [ ] SendHistoryDgvControl.cs - 顧客名検索の実装
### UIレベル(先頭ゼロ削除)
- [ ] SearchBoxControl.cs - MgmtNumberTxtBox_TextChangedメソッドの修正
- [ ] PatternSearchBoxControl.cs - MgmtNumberTxtBox_TextChangedメソッドの修正
- [ ] HistorySearchBoxControl.cs - MgmtNumberTxtBox_TextChangedメソッドの修正
### UIレベル(日付初期値)
- [ ] HistorySearchBoxControl.Designer.cs - dateTimePickerEndの固定日付削除
### 動作確認
- [ ] 顧客マスタの検索機能(管理番号、顧客名、未使用フラグ)
- [ ] 送信パターンマスタの検索機能(パターンID、パターン名、関連顧客)
- [ ] 送信履歴の検索機能(管理番号、顧客名、パターン名、日付範囲)
- [ ] 全画面の先頭ゼロ自動削除機能
- [ ] 送信履歴の日付選択が現在日付周辺で開くこと
---
## 注意事項
### 1. 先頭ゼロ削除機能
- ユーザーが「001」「002」のような先頭ゼロ付きの数値を入力した場合、自動的に「1」「2」に変換
- カーソル位置は変換後の文字列の末尾に移動
- DAOレベルでも同様の処理を実装して、検索の一貫性を保証
### 2. 送信履歴の検索実装
- 送信履歴テーブルには顧客情報が含まれないため、送信履歴詳細テーブルから検索
- 該当する送信履歴IDのリストを取得してフィルタリング
- 検索結果が0件の場合は空のリストを表示
### 3. Designer.csファイルの修正
- Designer.csは自動生成ファイルのため、Visual Studioのフォームデザイナーで再生成される可能性がある
- 恒久的な修正のためには、フォームデザイナーでプロパティを設定することを推奨
### 4. 日付初期値
- DateTimePickerのValueプロパティに固定日付を設定しない
- .NET Frameworkのデフォルト動作(現在の日時)を利用
### 5. 送信履歴の初期表示
- rdoScheduleSendSelection.Checked = true により、初期状態で定期送信が選択
- SendType = 0 のデータがDataGridViewに表示される
---
## 実装による効果
1. **完全な検索機能**
- すべての画面で設計された検索項目が完全に動作
- 送信履歴画面の未実装機能(管理番号、顧客名検索)が利用可能に
2. **ユーザビリティの向上**
- 先頭ゼロの自動削除により、入力ミスを防止
- 日付選択が現在日付周辺で開くことで、操作性が向上
3. **一貫性のある動作**
- 全画面で統一された検索動作
- 管理番号の処理が全画面で同一
---
## トラブルシューティング
### 問題1:検索が動作しない
**原因**:DAOメソッドが正しく実装されていない
**解決**:SendHistoryDetailDaoに追加したメソッドが正しく記述されているか確認
### 問題2:先頭ゼロが削除されない
**原因**:TextChangedイベントハンドラが正しく実装されていない
**解決**:各コントロールのMgmtNumberTxtBox_TextChangedメソッドを確認
### 問題3:日付が過去の固定日付で開く
**原因**:Designer.csにValueプロパティが残っている
**解決**:HistorySearchBoxControl.Designer.csの該当行を削除
### 問題4:送信履歴の初期表示が不定期送信になる
**原因**:rdoScheduleSendSelection.Checkedの設定が漏れている
**解決**:HistorySearchBoxControl.csのコンストラクタを確認
---
## 変更履歴
| 日付 | 内容 | 対応者 |
|------|------|--------|
| 2024/XX/XX | 初版作成 | - |
| 2024/XX/XX | 送信履歴の検索機能実装 | - |
| 2024/XX/XX | 先頭ゼロ自動削除機能追加 | - |
| 2024/XX/XX | 日付初期値修正 | - |
---
## 関連ドキュメント
- データベース設計書
- 画面設計書
- 楽観的ロック完全実装手順書
- MessageBoxUtil定数定義書
---
以上