第24章 Windowsフォームアプリで登録・更新・削除を行う
この章の目的
Section titled “この章の目的”この章では、WindowsフォームアプリからOracle Databaseに対して、社員情報の登録・更新・削除を行う方法を学習します。
第23章では、Oracle Databaseから社員一覧を取得し、DataGridView に表示しました。
Oracle Database ↓EmployeeRepository ↓List<EmployeeListItem> ↓DataGridViewこの章では、さらに次の操作を追加します。
登録更新削除つまり、これまで扱ってきたCRUDのうち、参照以外の操作もWindowsフォームアプリから実行します。
| 操作 | 意味 | SQL |
|---|---|---|
| Create | 登録 | INSERT |
| Read | 参照 | SELECT |
| Update | 更新 | UPDATE |
| Delete | 削除 | DELETE |
この章では、次のような流れを体験します。
フォームに社員情報を入力する ↓登録ボタンをクリックする ↓INSERT文を実行する ↓DataGridViewを再表示するDataGridViewで社員を選択する ↓入力欄に値を表示する ↓内容を変更する ↓更新ボタンをクリックする ↓UPDATE文を実行する ↓DataGridViewを再表示するDataGridViewで社員を選択する ↓削除ボタンをクリックする ↓確認メッセージを表示する ↓DELETE文を実行する ↓DataGridViewを再表示するこの章の目的は、Windowsフォームアプリで本格的な業務アプリを完成させることではありません。
目的は、画面入力、Repository、SQL実行、一覧再表示 の流れを理解することです。
初期データについて
Section titled “初期データについて”この研修では、必要に応じて初期データに戻すSQLを実行できる前提とします。
また、各受講者は自分のPC上のOracle Databaseを利用するため、他の受講者のデータに影響を与えることはありません。
そのため、この章では、既存の社員データに対する更新や削除も演習対象にできます。
ただし、削除処理は元に戻せない操作であるため、次の点には注意します。
削除前に確認メッセージを表示する誤って削除した場合は初期データ復元SQLを実行する本番環境では安易にDELETEを実行しない補足
実務では、削除処理は特に慎重に扱います。 物理削除ではなく、削除フラグを立てる論理削除を使うこともあります。 この章ではSQLの基本操作を体験するため、
DELETE文を使います。
挿絵・スクリーンショット案
Section titled “挿絵・スクリーンショット案”この章では、以下の画像を入れると理解しやすくなります。
図24-1 WinForms CRUDアプリの全体像図24-2 社員情報入力欄とDataGridViewを配置した画面図24-3 DataGridViewの選択行を入力欄に表示する流れ図24-4 登録後に一覧が更新される画面図24-5 削除確認メッセージ図24-6 Form、Repository、Oracle DBの役割分担画像を挿入する場合は、次のように書けます。
画像ファイルは、images フォルダにまとめると管理しやすくなります。
CSharpText/ ├─ 24_winforms_crud.md └─ images/ ├─ 24_winforms_crud_overview.png ├─ 24_form_layout.png ├─ 24_insert_result.png ├─ 24_delete_confirm.png └─ 24_repository_flow.pngこの章でできるようになること
Section titled “この章でできるようになること”この章を終えると、次のことができるようになります。
- Windowsフォームアプリから
INSERTを実行できる - Windowsフォームアプリから
UPDATEを実行できる - Windowsフォームアプリから
DELETEを実行できる ExecuteNonQueryの役割を説明できる- 画面の入力値をオブジェクトに変換できる
- DBのNULLにしたい値を
DBNull.Valueとして渡せる DataGridViewの選択行を入力欄に反映できる- 登録・更新・削除後に一覧を再表示できる
- 入力チェックを行える
- 削除前に確認メッセージを表示できる
- FormとRepositoryの役割分担を説明できる
本章で使用する環境
Section titled “本章で使用する環境”| 項目 | 内容 |
|---|---|
| 開発環境 | Visual Studio 2022 |
| プロジェクト種類 | Windows フォーム アプリ |
| 対象フレームワーク | .NET 8 |
| プロジェクト名 | Chapter24_WinFormsCrud |
| DB | Oracle Database |
| 接続ユーザー | pingt |
| 使用する表 | employees、departments |
| 追加するNuGetパッケージ | Oracle.ManagedDataAccess.Core |
作業前チェック
Section titled “作業前チェック”作業を始める前に、次の内容を確認してください。
- SQL*Plusで
pingtユーザーに接続できる -
employees表をSELECTできる - Windowsフォームアプリから社員一覧を表示できる
-
DataGridViewにList<T>を表示できる -
DataGridViewの選択行からオブジェクトを取得できる -
OracleConnection、OracleCommand、OracleDataReaderを使える -
INSERT、UPDATE、DELETEのSQLをおおまかに読める - 第23章の内容をGitに提出済みである
24-1 この章で作成する画面
Section titled “24-1 この章で作成する画面”この章では、次のような画面を作成します。
社員ID [ ]社員名 [ ]よみがな [ ]職種ID [ ]上司ID [ ]入社日 [ yyyy/mm/dd ]給与 [ ]歩合 [ ]部署ID [ ]
[一覧表示] [登録] [更新] [削除] [入力クリア]
件数:0件
+-------------------------------------------------------------+| 社員ID | 社員名 | 部署名 | 入社日 | 給与 |+-------------------------------------------------------------+基本操作は次の通りです。
一覧表示 DBから社員一覧を取得してDataGridViewに表示する
登録 入力欄の内容をemployees表にINSERTする
更新 選択した社員の内容を入力欄で変更し、UPDATEする
削除 選択した社員をDELETEする
入力クリア 入力欄を空にする24-2 プロジェクトを作成する
Section titled “24-2 プロジェクトを作成する”Visual Studio 2022で、Windowsフォームアプリを作成します。
1. 「新しいプロジェクトの作成」をクリックする2. 「Windows フォーム アプリ」を選択する3. 「次へ」をクリックする4. プロジェクト名に Chapter24_WinFormsCrud と入力する5. 保存場所を確認する6. 「次へ」をクリックする7. フレームワークで .NET 8.0 を選択する8. 「作成」をクリックする作成後、NuGetで次のパッケージを追加します。
Oracle.ManagedDataAccess.CoreOracle接続を行うクラスでは、次の using を使います。
using Oracle.ManagedDataAccess.Client;24-3 Modelクラスを作成する
Section titled “24-3 Modelクラスを作成する”EmployeeListItemクラス
Section titled “EmployeeListItemクラス”一覧表示用の EmployeeListItem クラスを作成します。
EmployeeListItem.cs を追加してください。
namespace Chapter24_WinFormsCrud{ public class EmployeeListItem { public int EmployeeId { get; set; } public string EmployeeName { get; set; } = ""; public string DepartmentName { get; set; } = ""; public DateTime HireDate { get; set; } public decimal? Salary { get; set; } }}このクラスは、DataGridViewに表示する1行分のデータです。
EmployeeEditModelクラス
Section titled “EmployeeEditModelクラス”登録・更新用の EmployeeEditModel クラスを作成します。
EmployeeEditModel.cs を追加してください。
namespace Chapter24_WinFormsCrud{ public class EmployeeEditModel { public int EmployeeId { get; set; } public string EmployeeName { get; set; } = ""; public string? Yomi { get; set; } public int JobId { get; set; } public int? ManagerId { get; set; } public DateTime HireDate { get; set; } public decimal? Salary { get; set; } public decimal? Commission { get; set; } public int DepartmentId { get; set; } }}このクラスは、入力欄の値をまとめて扱うために使います。
Formの入力欄 ↓EmployeeEditModel ↓Repository ↓INSERT / UPDATE24-4 EmployeeRepositoryを作成する
Section titled “24-4 EmployeeRepositoryを作成する”EmployeeRepository.cs を作成します。
まず、基本形を作ります。
using Oracle.ManagedDataAccess.Client;
namespace Chapter24_WinFormsCrud{ public class EmployeeRepository { private readonly string _connectionString = "User Id=pingt;Password=oracle;Data Source=localhost:1521/XEPDB1;";
public List<EmployeeListItem> GetEmployeeListItems() { List<EmployeeListItem> employees = new List<EmployeeListItem>();
string sql = @" SELECT e.employee_id, e.employee_name, d.department_name, e.hiredate, e.salary FROM employees e JOIN departments d ON e.department_id = d.department_id ORDER BY e.employee_id";
using (OracleConnection connection = new OracleConnection(_connectionString)) { connection.Open();
using (OracleCommand command = new OracleCommand(sql, connection)) using (OracleDataReader reader = command.ExecuteReader()) { while (reader.Read()) { EmployeeListItem employee = new EmployeeListItem();
employee.EmployeeId = Convert.ToInt32(reader["employee_id"]); employee.EmployeeName = reader["employee_name"].ToString() ?? ""; employee.DepartmentName = reader["department_name"].ToString() ?? ""; employee.HireDate = Convert.ToDateTime(reader["hiredate"]); employee.Salary = reader["salary"] == DBNull.Value ? null : Convert.ToDecimal(reader["salary"]);
employees.Add(employee); } } }
return employees; } }}これは第23章と同じように、社員一覧を取得する処理です。
24-5 登録処理を作成する
Section titled “24-5 登録処理を作成する”Insertメソッド
Section titled “Insertメソッド”EmployeeRepository に、登録用の Insert メソッドを追加します。
public void Insert(EmployeeEditModel employee){ string sql = @" INSERT INTO employees ( employee_id, employee_name, yomi, job_id, manager_id, hiredate, salary, commission, department_id ) VALUES ( :employeeId, :employeeName, :yomi, :jobId, :managerId, :hireDate, :salary, :commission, :departmentId )";
using (OracleConnection connection = new OracleConnection(_connectionString)) { connection.Open();
using (OracleCommand command = new OracleCommand(sql, connection)) { command.BindByName = true;
command.Parameters.Add("employeeId", OracleDbType.Int32).Value = employee.EmployeeId; command.Parameters.Add("employeeName", OracleDbType.Varchar2).Value = employee.EmployeeName; command.Parameters.Add("yomi", OracleDbType.Varchar2).Value = string.IsNullOrWhiteSpace(employee.Yomi) ? DBNull.Value : employee.Yomi; command.Parameters.Add("jobId", OracleDbType.Int32).Value = employee.JobId; command.Parameters.Add("managerId", OracleDbType.Int32).Value = employee.ManagerId.HasValue ? employee.ManagerId.Value : DBNull.Value; command.Parameters.Add("hireDate", OracleDbType.Date).Value = employee.HireDate; command.Parameters.Add("salary", OracleDbType.Decimal).Value = employee.Salary.HasValue ? employee.Salary.Value : DBNull.Value; command.Parameters.Add("commission", OracleDbType.Decimal).Value = employee.Commission.HasValue ? employee.Commission.Value : DBNull.Value; command.Parameters.Add("departmentId", OracleDbType.Int32).Value = employee.DepartmentId;
command.ExecuteNonQuery(); } }}ExecuteNonQuery
Section titled “ExecuteNonQuery”ExecuteNonQuery は、SELECTのように結果表を返さないSQLを実行するときに使います。
command.ExecuteNonQuery();主に次のSQLで使います。
INSERTUPDATEDELETESELECTでは、結果を読み取るために ExecuteReader を使いました。
OracleDataReader reader = command.ExecuteReader();CRUD処理では、この違いを意識しましょう。
24-6 更新用データ取得とUpdateを作成する
Section titled “24-6 更新用データ取得とUpdateを作成する”FindEditByIdメソッド
Section titled “FindEditByIdメソッド”更新時には、DataGridViewで選択した社員IDから、詳細な編集用データを取得します。
EmployeeRepository に次のメソッドを追加します。
public EmployeeEditModel? FindEditById(int employeeId){ string sql = @" SELECT employee_id, employee_name, yomi, job_id, manager_id, hiredate, salary, commission, department_id FROM employees WHERE employee_id = :employeeId";
using (OracleConnection connection = new OracleConnection(_connectionString)) { connection.Open();
using (OracleCommand command = new OracleCommand(sql, connection)) { command.BindByName = true; command.Parameters.Add("employeeId", OracleDbType.Int32).Value = employeeId;
using (OracleDataReader reader = command.ExecuteReader()) { if (reader.Read()) { EmployeeEditModel employee = new EmployeeEditModel();
employee.EmployeeId = Convert.ToInt32(reader["employee_id"]); employee.EmployeeName = reader["employee_name"].ToString() ?? ""; employee.Yomi = reader["yomi"] == DBNull.Value ? null : reader["yomi"].ToString(); employee.JobId = Convert.ToInt32(reader["job_id"]); employee.ManagerId = reader["manager_id"] == DBNull.Value ? null : Convert.ToInt32(reader["manager_id"]); employee.HireDate = Convert.ToDateTime(reader["hiredate"]); employee.Salary = reader["salary"] == DBNull.Value ? null : Convert.ToDecimal(reader["salary"]); employee.Commission = reader["commission"] == DBNull.Value ? null : Convert.ToDecimal(reader["commission"]); employee.DepartmentId = Convert.ToInt32(reader["department_id"]);
return employee; } } } }
return null;}Updateメソッド
Section titled “Updateメソッド”続いて、更新用の Update メソッドを追加します。
public int Update(EmployeeEditModel employee){ string sql = @" UPDATE employees SET employee_name = :employeeName, yomi = :yomi, job_id = :jobId, manager_id = :managerId, hiredate = :hireDate, salary = :salary, commission = :commission, department_id = :departmentId WHERE employee_id = :employeeId";
using (OracleConnection connection = new OracleConnection(_connectionString)) { connection.Open();
using (OracleCommand command = new OracleCommand(sql, connection)) { command.BindByName = true;
command.Parameters.Add("employeeName", OracleDbType.Varchar2).Value = employee.EmployeeName; command.Parameters.Add("yomi", OracleDbType.Varchar2).Value = string.IsNullOrWhiteSpace(employee.Yomi) ? DBNull.Value : employee.Yomi; command.Parameters.Add("jobId", OracleDbType.Int32).Value = employee.JobId; command.Parameters.Add("managerId", OracleDbType.Int32).Value = employee.ManagerId.HasValue ? employee.ManagerId.Value : DBNull.Value; command.Parameters.Add("hireDate", OracleDbType.Date).Value = employee.HireDate; command.Parameters.Add("salary", OracleDbType.Decimal).Value = employee.Salary.HasValue ? employee.Salary.Value : DBNull.Value; command.Parameters.Add("commission", OracleDbType.Decimal).Value = employee.Commission.HasValue ? employee.Commission.Value : DBNull.Value; command.Parameters.Add("departmentId", OracleDbType.Int32).Value = employee.DepartmentId; command.Parameters.Add("employeeId", OracleDbType.Int32).Value = employee.EmployeeId;
return command.ExecuteNonQuery(); } }}ExecuteNonQuery は、更新された行数を返します。
int count = command.ExecuteNonQuery();更新対象が見つからない場合は、0 が返ります。
24-7 削除処理を作成する
Section titled “24-7 削除処理を作成する”EmployeeRepository に、削除用の Delete メソッドを追加します。
public int Delete(int employeeId){ string sql = @" DELETE FROM employees WHERE employee_id = :employeeId";
using (OracleConnection connection = new OracleConnection(_connectionString)) { connection.Open();
using (OracleCommand command = new OracleCommand(sql, connection)) { command.BindByName = true; command.Parameters.Add("employeeId", OracleDbType.Int32).Value = employeeId;
return command.ExecuteNonQuery(); } }}削除された行数が戻り値になります。
1 1件削除された
0 対象データが見つからなかった24-8 フォームにコントロールを配置する
Section titled “24-8 フォームにコントロールを配置する”フォームに次のコントロールを配置します。
| コントロール | Name | Text |
|---|---|---|
Label | lblEmployeeId | 社員ID |
TextBox | txtEmployeeId | 空欄 |
Label | lblEmployeeName | 社員名 |
TextBox | txtEmployeeName | 空欄 |
Label | lblYomi | よみがな |
TextBox | txtYomi | 空欄 |
Label | lblJobId | 職種ID |
TextBox | txtJobId | 空欄 |
Label | lblManagerId | 上司ID |
TextBox | txtManagerId | 空欄 |
Label | lblHireDate | 入社日 |
DateTimePicker | dtpHireDate | なし |
Label | lblSalary | 給与 |
TextBox | txtSalary | 空欄 |
Label | lblCommission | 歩合 |
TextBox | txtCommission | 空欄 |
Label | lblDepartmentId | 部署ID |
TextBox | txtDepartmentId | 空欄 |
Button | btnLoad | 一覧表示 |
Button | btnInsert | 登録 |
Button | btnUpdate | 更新 |
Button | btnDelete | 削除 |
Button | btnClearInput | 入力クリア |
Label | lblCount | 件数:0件 |
DataGridView | dgvEmployees | なし |
DataGridViewの設定
Section titled “DataGridViewの設定”dgvEmployees には次の設定を行います。
| プロパティ | 設定値 |
|---|---|
ReadOnly | True |
AllowUserToAddRows | False |
SelectionMode | FullRowSelect |
MultiSelect | False |
AutoSizeColumnsMode | Fill |
コードで設定する場合は、次のメソッドを使います。
private void SetupDataGridView(){ dgvEmployees.ReadOnly = true; dgvEmployees.AllowUserToAddRows = false; dgvEmployees.SelectionMode = DataGridViewSelectionMode.FullRowSelect; dgvEmployees.MultiSelect = false; dgvEmployees.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;}24-9 Form1の基本コードを作成する
Section titled “24-9 Form1の基本コードを作成する”Form1.cs に、基本となるフィールドと初期設定を書きます。
using Oracle.ManagedDataAccess.Client;
namespace Chapter24_WinFormsCrud{ public partial class Form1 : Form { private List<EmployeeListItem> _employees = new List<EmployeeListItem>();
public Form1() { InitializeComponent();
SetupDataGridView(); }
private void SetupDataGridView() { dgvEmployees.ReadOnly = true; dgvEmployees.AllowUserToAddRows = false; dgvEmployees.SelectionMode = DataGridViewSelectionMode.FullRowSelect; dgvEmployees.MultiSelect = false; dgvEmployees.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill; } }}24-10 一覧表示処理を作成する
Section titled “24-10 一覧表示処理を作成する”DisplayEmployeesメソッド
Section titled “DisplayEmployeesメソッド”DataGridViewに社員一覧を表示するメソッドを作成します。
private void DisplayEmployees(List<EmployeeListItem> employees){ dgvEmployees.DataSource = null; dgvEmployees.DataSource = employees;
lblCount.Text = $"件数:{employees.Count}件";
SetColumnHeaders();}SetColumnHeadersメソッド
Section titled “SetColumnHeadersメソッド”列見出しを日本語にします。
private void SetColumnHeaders(){ if (dgvEmployees.Columns["EmployeeId"] != null) { dgvEmployees.Columns["EmployeeId"].HeaderText = "社員ID"; }
if (dgvEmployees.Columns["EmployeeName"] != null) { dgvEmployees.Columns["EmployeeName"].HeaderText = "社員名"; }
if (dgvEmployees.Columns["DepartmentName"] != null) { dgvEmployees.Columns["DepartmentName"].HeaderText = "部署名"; }
if (dgvEmployees.Columns["HireDate"] != null) { dgvEmployees.Columns["HireDate"].HeaderText = "入社日"; }
if (dgvEmployees.Columns["Salary"] != null) { dgvEmployees.Columns["Salary"].HeaderText = "給与"; }}LoadEmployeesメソッド
Section titled “LoadEmployeesメソッド”DBから一覧を取得して表示する処理をメソッドにします。
private void LoadEmployees(){ EmployeeRepository repository = new EmployeeRepository();
_employees = repository.GetEmployeeListItems();
DisplayEmployees(_employees);}一覧表示ボタン
Section titled “一覧表示ボタン”btnLoad のクリックイベントを作成します。
private void btnLoad_Click(object sender, EventArgs e){ try { LoadEmployees(); } catch (OracleException ex) { MessageBox.Show("Oracle Database処理中にエラーが発生しました。\n" + ex.Message); } catch (Exception ex) { MessageBox.Show("予期しないエラーが発生しました。\n" + ex.Message); }}24-11 入力値をEmployeeEditModelに変換する
Section titled “24-11 入力値をEmployeeEditModelに変換する”入力欄から値を取得するメソッド
Section titled “入力欄から値を取得するメソッド”登録・更新では、入力欄の内容を EmployeeEditModel に変換します。
private EmployeeEditModel? CreateEmployeeEditModelFromInput(){ if (!int.TryParse(txtEmployeeId.Text.Trim(), out int employeeId)) { MessageBox.Show("社員IDは整数で入力してください。"); return null; }
string employeeName = txtEmployeeName.Text.Trim();
if (string.IsNullOrWhiteSpace(employeeName)) { MessageBox.Show("社員名を入力してください。"); return null; }
string? yomi = string.IsNullOrWhiteSpace(txtYomi.Text) ? null : txtYomi.Text.Trim();
if (!int.TryParse(txtJobId.Text.Trim(), out int jobId)) { MessageBox.Show("職種IDは整数で入力してください。"); return null; }
int? managerId = null; string managerIdText = txtManagerId.Text.Trim();
if (!string.IsNullOrWhiteSpace(managerIdText)) { if (!int.TryParse(managerIdText, out int parsedManagerId)) { MessageBox.Show("上司IDは整数で入力してください。"); return null; }
managerId = parsedManagerId; }
decimal? salary = null; string salaryText = txtSalary.Text.Trim();
if (!string.IsNullOrWhiteSpace(salaryText)) { if (!decimal.TryParse(salaryText, out decimal parsedSalary)) { MessageBox.Show("給与は数値で入力してください。"); return null; }
salary = parsedSalary; }
decimal? commission = null; string commissionText = txtCommission.Text.Trim();
if (!string.IsNullOrWhiteSpace(commissionText)) { if (!decimal.TryParse(commissionText, out decimal parsedCommission)) { MessageBox.Show("歩合は数値で入力してください。"); return null; }
commission = parsedCommission; }
if (!int.TryParse(txtDepartmentId.Text.Trim(), out int departmentId)) { MessageBox.Show("部署IDは整数で入力してください。"); return null; }
EmployeeEditModel employee = new EmployeeEditModel { EmployeeId = employeeId, EmployeeName = employeeName, Yomi = yomi, JobId = jobId, ManagerId = managerId, HireDate = dtpHireDate.Value.Date, Salary = salary, Commission = commission, DepartmentId = departmentId };
return employee;}nullにしたい値
Section titled “nullにしたい値”次の項目は、空欄なら null として扱います。
よみがな上司ID給与歩合画面上では空欄ですが、Repositoryではこれらを DBNull.Value に変換してDBに渡します。
画面の空欄 ↓C#のnull ↓DBのNULL24-12 入力欄をクリアする
Section titled “24-12 入力欄をクリアする”入力欄をクリアするメソッドを作成します。
private void ClearInput(){ txtEmployeeId.Clear(); txtEmployeeName.Clear(); txtYomi.Clear(); txtJobId.Clear(); txtManagerId.Clear(); dtpHireDate.Value = DateTime.Today; txtSalary.Clear(); txtCommission.Clear(); txtDepartmentId.Clear();
txtEmployeeId.Focus();}btnClearInput のクリックイベントで呼び出します。
private void btnClearInput_Click(object sender, EventArgs e){ ClearInput();}24-13 登録処理を作成する
Section titled “24-13 登録処理を作成する”btnInsert のクリックイベントを作成します。
private void btnInsert_Click(object sender, EventArgs e){ EmployeeEditModel? employee = CreateEmployeeEditModelFromInput();
if (employee == null) { return; }
try { EmployeeRepository repository = new EmployeeRepository();
repository.Insert(employee);
MessageBox.Show("社員情報を登録しました。");
LoadEmployees();
ClearInput(); } catch (OracleException ex) { MessageBox.Show("Oracle Database処理中にエラーが発生しました。\n" + ex.Message); } catch (Exception ex) { MessageBox.Show("予期しないエラーが発生しました。\n" + ex.Message); }}登録後は、一覧を再取得します。
LoadEmployees();これにより、登録したデータがDataGridViewに反映されます。
24-14 DataGridViewの選択行を入力欄に表示する
Section titled “24-14 DataGridViewの選択行を入力欄に表示する”CellClickイベントを使う
Section titled “CellClickイベントを使う”DataGridViewの行をクリックしたときに、その社員の詳細データを取得し、入力欄に表示します。
dgvEmployees の CellClick イベントを作成します。
private void dgvEmployees_CellClick(object sender, DataGridViewCellEventArgs e){ if (dgvEmployees.CurrentRow == null) { return; }
EmployeeListItem? selectedEmployee = dgvEmployees.CurrentRow.DataBoundItem as EmployeeListItem;
if (selectedEmployee == null) { return; }
try { EmployeeRepository repository = new EmployeeRepository();
EmployeeEditModel? employee = repository.FindEditById(selectedEmployee.EmployeeId);
if (employee == null) { MessageBox.Show("社員情報を取得できませんでした。"); return; }
SetInputValues(employee); } catch (OracleException ex) { MessageBox.Show("Oracle Database処理中にエラーが発生しました。\n" + ex.Message); } catch (Exception ex) { MessageBox.Show("予期しないエラーが発生しました。\n" + ex.Message); }}入力欄に値を設定するメソッド
Section titled “入力欄に値を設定するメソッド”private void SetInputValues(EmployeeEditModel employee){ txtEmployeeId.Text = employee.EmployeeId.ToString(); txtEmployeeName.Text = employee.EmployeeName; txtYomi.Text = employee.Yomi ?? ""; txtJobId.Text = employee.JobId.ToString(); txtManagerId.Text = employee.ManagerId.HasValue ? employee.ManagerId.Value.ToString() : ""; dtpHireDate.Value = employee.HireDate; txtSalary.Text = employee.Salary.HasValue ? employee.Salary.Value.ToString() : ""; txtCommission.Text = employee.Commission.HasValue ? employee.Commission.Value.ToString() : ""; txtDepartmentId.Text = employee.DepartmentId.ToString();}これで、DataGridViewで行を選択すると、入力欄に現在の社員情報が表示されます。
24-15 更新処理を作成する
Section titled “24-15 更新処理を作成する”btnUpdate のクリックイベントを作成します。
private void btnUpdate_Click(object sender, EventArgs e){ EmployeeEditModel? employee = CreateEmployeeEditModelFromInput();
if (employee == null) { return; }
try { EmployeeRepository repository = new EmployeeRepository();
int count = repository.Update(employee);
if (count == 0) { MessageBox.Show("更新対象の社員が見つかりませんでした。"); return; }
MessageBox.Show("社員情報を更新しました。");
LoadEmployees();
ClearInput(); } catch (OracleException ex) { MessageBox.Show("Oracle Database処理中にエラーが発生しました。\n" + ex.Message); } catch (Exception ex) { MessageBox.Show("予期しないエラーが発生しました。\n" + ex.Message); }}更新後も、一覧を再取得します。
LoadEmployees();24-16 削除処理を作成する
Section titled “24-16 削除処理を作成する”選択された社員IDを取得する
Section titled “選択された社員IDを取得する”削除は、DataGridViewで選択されている行を対象にします。
private int? GetSelectedEmployeeId(){ if (dgvEmployees.CurrentRow == null) { return null; }
EmployeeListItem? employee = dgvEmployees.CurrentRow.DataBoundItem as EmployeeListItem;
if (employee == null) { return null; }
return employee.EmployeeId;}削除ボタンの処理
Section titled “削除ボタンの処理”btnDelete のクリックイベントを作成します。
private void btnDelete_Click(object sender, EventArgs e){ int? employeeId = GetSelectedEmployeeId();
if (!employeeId.HasValue) { MessageBox.Show("削除する社員を選択してください。"); return; }
DialogResult result = MessageBox.Show( $"社員ID {employeeId.Value} を削除します。よろしいですか?", "削除確認", MessageBoxButtons.YesNo, MessageBoxIcon.Warning );
if (result != DialogResult.Yes) { return; }
try { EmployeeRepository repository = new EmployeeRepository();
int count = repository.Delete(employeeId.Value);
if (count == 0) { MessageBox.Show("削除対象の社員が見つかりませんでした。"); return; }
MessageBox.Show("社員情報を削除しました。");
LoadEmployees();
ClearInput(); } catch (OracleException ex) { MessageBox.Show("Oracle Database処理中にエラーが発生しました。\n" + ex.Message); } catch (Exception ex) { MessageBox.Show("予期しないエラーが発生しました。\n" + ex.Message); }}削除確認の重要性
Section titled “削除確認の重要性”削除は、登録や更新よりも慎重に扱う必要があります。
この章では、削除前に必ず確認メッセージを表示します。
MessageBox.Show( "削除します。よろしいですか?", "削除確認", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);利用者が Yes を選んだ場合だけ削除します。
24-17 この章の処理の流れ
Section titled “24-17 この章の処理の流れ”1. 入力欄に社員情報を入力する2. 登録ボタンをクリックする3. 入力値をEmployeeEditModelに変換する4. EmployeeRepository.Insertを呼び出す5. INSERT文を実行する6. 一覧を再取得する7. 入力欄をクリアする1. DataGridViewで社員を選択する2. DBから編集用データを取得する3. 入力欄に値を表示する4. 入力欄の値を修正する5. 更新ボタンをクリックする6. EmployeeRepository.Updateを呼び出す7. UPDATE文を実行する8. 一覧を再取得する1. DataGridViewで社員を選択する2. 削除ボタンをクリックする3. 削除確認メッセージを表示する4. Yesが選択された場合だけ削除する5. EmployeeRepository.Deleteを呼び出す6. DELETE文を実行する7. 一覧を再取得する24-18 よくあるつまずき
Section titled “24-18 よくあるつまずき”| つまずき | 原因 | 対応 |
|---|---|---|
| 登録で主キーエラーになる | 同じ社員IDが既に存在する | 未使用の社員IDを指定する |
| 登録で外部キーエラーになる | 存在しない部署IDを指定している | departments に存在する部署IDを指定する |
| 登録で数値変換エラーになる | 数値欄に文字を入力している | TryParse で入力チェックする |
| NULLにしたい項目でエラーになる | DBNull.Value を渡していない | 空欄はnullにし、Repositoryで DBNull.Value にする |
| 更新しても値が変わらない | 対象社員IDが存在しない | DataGridViewから選択してから更新する |
| 削除しても消えない | 削除後に一覧を再表示していない | LoadEmployees() を呼ぶ |
| DataGridViewの選択行が取得できない | 行を選択していない | CurrentRow を確認する |
| CellClickイベントが動かない | イベントが関連付いていない | デザイナーでイベントを確認する |
| 入力欄が更新されない | SetInputValues を呼んでいない | CellClick処理を確認する |
| SQL実行時にORAエラーが出る | SQLや制約の問題 | エラーメッセージを確認する |
学んだことチェック
Section titled “学んだことチェック”次の項目について、自分で説明できるか確認してください。
- Windowsフォームアプリから
INSERTを実行できる - Windowsフォームアプリから
UPDATEを実行できる - Windowsフォームアプリから
DELETEを実行できる -
ExecuteNonQueryの役割を説明できる - 入力欄の値を
EmployeeEditModelに変換できる - 空欄をC#の
nullとして扱える - Repositoryで
nullをDBNull.Valueに変換できる - DataGridViewの選択行から社員IDを取得できる
- 選択行の社員情報を入力欄に表示できる
- 登録・更新・削除後に一覧を再表示できる
- 削除前に確認メッセージを表示できる
- FormとRepositoryの役割分担を説明できる
研修の進め方によっては、隣の人または近くの人と説明確認を行います。
次の内容を、自分の言葉で説明してください。
ExecuteReaderとExecuteNonQueryの違いは何ですか。- 登録処理では、画面の入力値をどのような流れでDBへ渡しますか。
- 空欄をDBのNULLとして登録するには、どのような変換が必要ですか。
- 更新処理では、なぜ先にDataGridViewで社員を選択するのですか。
- 削除処理で確認メッセージを表示する理由は何ですか。
- 登録・更新・削除後に
LoadEmployees()を呼ぶ理由は何ですか。 - FormにSQLを直接書かず、Repositoryに分ける理由は何ですか。
この章の演習課題に取り組みます。
制限時間は 100分 です。
時間内にすべて完成しなくても構いません。
できたところまでを保存し、Gitに提出してください。
課題24-1 Windowsフォームアプリを作成する
Section titled “課題24-1 Windowsフォームアプリを作成する”Windowsフォームアプリのプロジェクトを作成してください。
条件:
- プロジェクト名は
Chapter24_WinFormsCrudとする - フレームワークは
.NET 8.0を選択する - NuGetで
Oracle.ManagedDataAccess.Coreを追加する
課題24-2 EmployeeEditModelを作成する
Section titled “課題24-2 EmployeeEditModelを作成する”登録・更新用の EmployeeEditModel クラスを作成してください。
条件:
EmployeeIdEmployeeNameYomiJobIdManagerIdHireDateSalaryCommissionDepartmentId
をプロパティとして持つこと。
課題24-3 RepositoryにInsertを追加する
Section titled “課題24-3 RepositoryにInsertを追加する”EmployeeRepository に登録用の Insert メソッドを追加してください。
条件:
INSERT INTO employeesを使う- SQLパラメーターを使う
ExecuteNonQueryを使う- NULL項目は
DBNull.Valueにする
課題24-4 登録ボタンを作成する
Section titled “課題24-4 登録ボタンを作成する”入力欄の内容をDBに登録できるようにしてください。
条件:
- 入力値を
EmployeeEditModelに変換する repository.Insert(employee)を呼び出す- 登録後に一覧を再表示する
- 登録後に入力欄をクリアする
課題24-5 選択行を入力欄に表示する
Section titled “課題24-5 選択行を入力欄に表示する”DataGridViewで選択した社員の情報を、入力欄に表示してください。
条件:
CellClickイベントを使う- 選択行の社員IDを取得する
- Repositoryで詳細データを取得する
- 入力欄に値を設定する
課題24-6 更新処理を作成する
Section titled “課題24-6 更新処理を作成する”入力欄の内容で社員情報を更新してください。
条件:
- Repositoryに
Updateメソッドを作成する UPDATE employeesを使う- SQLパラメーターを使う
- 更新後に一覧を再表示する
課題24-7 削除処理を作成する
Section titled “課題24-7 削除処理を作成する”選択した社員を削除してください。
条件:
- Repositoryに
Deleteメソッドを作成する DELETE FROM employeesを使う- 削除前に確認メッセージを表示する
- 削除後に一覧を再表示する
課題24-8 入力チェックを強化する
Section titled “課題24-8 入力チェックを強化する”登録・更新時の入力チェックを追加してください。
条件:
- 社員IDは整数
- 社員名は必須
- 職種IDは整数
- 部署IDは整数
- 給与は空欄または数値
- 歩合は空欄または数値
課題24-9 初期データ復元SQLを実行して確認する
Section titled “課題24-9 初期データ復元SQLを実行して確認する”データを変更した後、初期データ復元SQLを実行して元に戻してください。
条件:
- 登録・更新・削除を行う
- SQL*Plusまたは指定されたツールで初期データ復元SQLを実行する
- 一覧表示を行い、データが戻ったことを確認する
Gitへの提出
Section titled “Gitへの提出”課題が終わったら、できたところまでをGitに提出します。
git statusgit add .git commit -m "Chapter24 WinForms CRUD処理"git pushGitの操作でエラーが出た場合は、自己判断で同じ操作を繰り返さず、講師に確認してください。
提出前チェックリスト
Section titled “提出前チェックリスト”- Windowsフォームアプリを作成している
-
Oracle.ManagedDataAccess.Coreを追加している -
EmployeeEditModelを作成している -
EmployeeRepository.Insertを作成している -
EmployeeRepository.Updateを作成している -
EmployeeRepository.Deleteを作成している - 入力欄から
EmployeeEditModelを作成できる - 登録処理が動作する
- 更新処理が動作する
- 削除処理が動作する
- 削除前に確認メッセージを表示している
- 登録・更新・削除後に一覧を再表示している
- NULL項目に
DBNull.Valueを渡している - 入力チェックを行っている
- Gitにcommitしている
- Gitにpushしている
この章のまとめ
Section titled “この章のまとめ”この章では、WindowsフォームアプリからOracle Databaseに対して、登録・更新・削除を行う方法を学習しました。
この章で学んだ主な内容は次の通りです。
- CRUDは、Create、Read、Update、Deleteの基本操作である
INSERT、UPDATE、DELETEではExecuteNonQueryを使う- 画面の入力値は、
EmployeeEditModelに変換して扱うと整理しやすい - 空欄をDBのNULLにしたい場合は、C#側では
null、DBへ渡すときはDBNull.Valueを使う - DataGridViewの選択行から社員IDを取得できる
- 選択した社員の詳細情報を入力欄に表示できる
- 登録・更新・削除後は、一覧を再取得して画面を更新する
- 削除処理では確認メッセージを表示する
- Formは画面操作を担当し、RepositoryはDBアクセスを担当する
- 初期データ復元SQLがあれば、演習後にデータを元に戻せる
次章では、研修全体のまとめと小さな総合演習 を行います。
コンソールアプリ、Webアプリ、Windowsフォームアプリ、Oracle Database接続を振り返り、現場で既存システムを読むために重要な観点を整理します。