Skip to content

第24章 Windowsフォームアプリで登録・更新・削除を行う

この章では、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実行、一覧再表示 の流れを理解することです。


この研修では、必要に応じて初期データに戻すSQLを実行できる前提とします。

また、各受講者は自分のPC上のOracle Databaseを利用するため、他の受講者のデータに影響を与えることはありません。

そのため、この章では、既存の社員データに対する更新や削除も演習対象にできます。

ただし、削除処理は元に戻せない操作であるため、次の点には注意します。

削除前に確認メッセージを表示する
誤って削除した場合は初期データ復元SQLを実行する
本番環境では安易にDELETEを実行しない

補足

実務では、削除処理は特に慎重に扱います。 物理削除ではなく、削除フラグを立てる論理削除を使うこともあります。 この章ではSQLの基本操作を体験するため、DELETE 文を使います。


この章では、以下の画像を入れると理解しやすくなります。

図24-1 WinForms CRUDアプリの全体像
図24-2 社員情報入力欄とDataGridViewを配置した画面
図24-3 DataGridViewの選択行を入力欄に表示する流れ
図24-4 登録後に一覧が更新される画面
図24-5 削除確認メッセージ
図24-6 Form、Repository、Oracle DBの役割分担

画像を挿入する場合は、次のように書けます。

![WinForms CRUDアプリの画面例](images/24_winforms_crud_screen.png)

画像ファイルは、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の役割分担を説明できる

項目内容
開発環境Visual Studio 2022
プロジェクト種類Windows フォーム アプリ
対象フレームワーク.NET 8
プロジェクト名Chapter24_WinFormsCrud
DBOracle Database
接続ユーザーpingt
使用する表employeesdepartments
追加するNuGetパッケージOracle.ManagedDataAccess.Core

作業を始める前に、次の内容を確認してください。

  • SQL*Plusで pingt ユーザーに接続できる
  • employees 表をSELECTできる
  • Windowsフォームアプリから社員一覧を表示できる
  • DataGridViewList<T> を表示できる
  • DataGridView の選択行からオブジェクトを取得できる
  • OracleConnectionOracleCommandOracleDataReader を使える
  • INSERTUPDATEDELETE のSQLをおおまかに読める
  • 第23章の内容をGitに提出済みである

この章では、次のような画面を作成します。

社員ID [ ]
社員名 [ ]
よみがな [ ]
職種ID [ ]
上司ID [ ]
入社日 [ yyyy/mm/dd ]
給与 [ ]
歩合 [ ]
部署ID [ ]
[一覧表示] [登録] [更新] [削除] [入力クリア]
件数:0件
+-------------------------------------------------------------+
| 社員ID | 社員名 | 部署名 | 入社日 | 給与 |
+-------------------------------------------------------------+

基本操作は次の通りです。

一覧表示
DBから社員一覧を取得してDataGridViewに表示する
登録
入力欄の内容をemployees表にINSERTする
更新
選択した社員の内容を入力欄で変更し、UPDATEする
削除
選択した社員をDELETEする
入力クリア
入力欄を空にする

Visual Studio 2022で、Windowsフォームアプリを作成します。

1. 「新しいプロジェクトの作成」をクリックする
2. 「Windows フォーム アプリ」を選択する
3. 「次へ」をクリックする
4. プロジェクト名に Chapter24_WinFormsCrud と入力する
5. 保存場所を確認する
6. 「次へ」をクリックする
7. フレームワークで .NET 8.0 を選択する
8. 「作成」をクリックする

作成後、NuGetで次のパッケージを追加します。

Oracle.ManagedDataAccess.Core

Oracle接続を行うクラスでは、次の using を使います。

using Oracle.ManagedDataAccess.Client;

一覧表示用の 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 クラスを作成します。

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 / UPDATE

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章と同じように、社員一覧を取得する処理です。


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 は、SELECTのように結果表を返さないSQLを実行するときに使います。

command.ExecuteNonQuery();

主に次のSQLで使います。

INSERT
UPDATE
DELETE

SELECTでは、結果を読み取るために ExecuteReader を使いました。

OracleDataReader reader = command.ExecuteReader();

CRUD処理では、この違いを意識しましょう。


24-6 更新用データ取得とUpdateを作成する

Section titled “24-6 更新用データ取得とUpdateを作成する”

更新時には、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 メソッドを追加します。

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 が返ります。


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 フォームにコントロールを配置する”

フォームに次のコントロールを配置します。

コントロールNameText
LabellblEmployeeId社員ID
TextBoxtxtEmployeeId空欄
LabellblEmployeeName社員名
TextBoxtxtEmployeeName空欄
LabellblYomiよみがな
TextBoxtxtYomi空欄
LabellblJobId職種ID
TextBoxtxtJobId空欄
LabellblManagerId上司ID
TextBoxtxtManagerId空欄
LabellblHireDate入社日
DateTimePickerdtpHireDateなし
LabellblSalary給与
TextBoxtxtSalary空欄
LabellblCommission歩合
TextBoxtxtCommission空欄
LabellblDepartmentId部署ID
TextBoxtxtDepartmentId空欄
ButtonbtnLoad一覧表示
ButtonbtnInsert登録
ButtonbtnUpdate更新
ButtonbtnDelete削除
ButtonbtnClearInput入力クリア
LabellblCount件数:0件
DataGridViewdgvEmployeesなし

dgvEmployees には次の設定を行います。

プロパティ設定値
ReadOnlyTrue
AllowUserToAddRowsFalse
SelectionModeFullRowSelect
MultiSelectFalse
AutoSizeColumnsModeFill

コードで設定する場合は、次のメソッドを使います。

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;
}
}
}

DataGridViewに社員一覧を表示するメソッドを作成します。

private void DisplayEmployees(List<EmployeeListItem> employees)
{
dgvEmployees.DataSource = null;
dgvEmployees.DataSource = employees;
lblCount.Text = $"件数:{employees.Count}";
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 = "給与";
}
}

DBから一覧を取得して表示する処理をメソッドにします。

private void LoadEmployees()
{
EmployeeRepository repository = new EmployeeRepository();
_employees = repository.GetEmployeeListItems();
DisplayEmployees(_employees);
}

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 として扱います。

よみがな
上司ID
給与
歩合

画面上では空欄ですが、Repositoryではこれらを DBNull.Value に変換してDBに渡します。

画面の空欄
C#のnull
DBのNULL

入力欄をクリアするメソッドを作成します。

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();
}

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の選択行を入力欄に表示する”

DataGridViewの行をクリックしたときに、その社員の詳細データを取得し、入力欄に表示します。

dgvEmployeesCellClick イベントを作成します。

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で行を選択すると、入力欄に現在の社員情報が表示されます。


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();

削除は、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;
}

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);
}
}

削除は、登録や更新よりも慎重に扱う必要があります。

この章では、削除前に必ず確認メッセージを表示します。

MessageBox.Show(
"削除します。よろしいですか?",
"削除確認",
MessageBoxButtons.YesNo,
MessageBoxIcon.Warning
);

利用者が Yes を選んだ場合だけ削除します。


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. 一覧を再取得する

つまずき原因対応
登録で主キーエラーになる同じ社員IDが既に存在する未使用の社員IDを指定する
登録で外部キーエラーになる存在しない部署IDを指定しているdepartments に存在する部署IDを指定する
登録で数値変換エラーになる数値欄に文字を入力しているTryParse で入力チェックする
NULLにしたい項目でエラーになるDBNull.Value を渡していない空欄はnullにし、Repositoryで DBNull.Value にする
更新しても値が変わらない対象社員IDが存在しないDataGridViewから選択してから更新する
削除しても消えない削除後に一覧を再表示していないLoadEmployees() を呼ぶ
DataGridViewの選択行が取得できない行を選択していないCurrentRow を確認する
CellClickイベントが動かないイベントが関連付いていないデザイナーでイベントを確認する
入力欄が更新されないSetInputValues を呼んでいないCellClick処理を確認する
SQL実行時にORAエラーが出るSQLや制約の問題エラーメッセージを確認する

次の項目について、自分で説明できるか確認してください。

  • Windowsフォームアプリから INSERT を実行できる
  • Windowsフォームアプリから UPDATE を実行できる
  • Windowsフォームアプリから DELETE を実行できる
  • ExecuteNonQuery の役割を説明できる
  • 入力欄の値を EmployeeEditModel に変換できる
  • 空欄をC#の null として扱える
  • Repositoryで nullDBNull.Value に変換できる
  • DataGridViewの選択行から社員IDを取得できる
  • 選択行の社員情報を入力欄に表示できる
  • 登録・更新・削除後に一覧を再表示できる
  • 削除前に確認メッセージを表示できる
  • FormとRepositoryの役割分担を説明できる

研修の進め方によっては、隣の人または近くの人と説明確認を行います。

次の内容を、自分の言葉で説明してください。

  1. ExecuteReaderExecuteNonQuery の違いは何ですか。
  2. 登録処理では、画面の入力値をどのような流れでDBへ渡しますか。
  3. 空欄をDBのNULLとして登録するには、どのような変換が必要ですか。
  4. 更新処理では、なぜ先にDataGridViewで社員を選択するのですか。
  5. 削除処理で確認メッセージを表示する理由は何ですか。
  6. 登録・更新・削除後に LoadEmployees() を呼ぶ理由は何ですか。
  7. 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 クラスを作成してください。

条件:

  • EmployeeId
  • EmployeeName
  • Yomi
  • JobId
  • ManagerId
  • HireDate
  • Salary
  • Commission
  • DepartmentId

をプロパティとして持つこと。


課題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で詳細データを取得する
  • 入力欄に値を設定する

入力欄の内容で社員情報を更新してください。

条件:

  • Repositoryに Update メソッドを作成する
  • UPDATE employees を使う
  • SQLパラメーターを使う
  • 更新後に一覧を再表示する

選択した社員を削除してください。

条件:

  • 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に提出します。

Terminal window
git status
git add .
git commit -m "Chapter24 WinForms CRUD処理"
git push

Gitの操作でエラーが出た場合は、自己判断で同じ操作を繰り返さず、講師に確認してください。


  • Windowsフォームアプリを作成している
  • Oracle.ManagedDataAccess.Core を追加している
  • EmployeeEditModel を作成している
  • EmployeeRepository.Insert を作成している
  • EmployeeRepository.Update を作成している
  • EmployeeRepository.Delete を作成している
  • 入力欄から EmployeeEditModel を作成できる
  • 登録処理が動作する
  • 更新処理が動作する
  • 削除処理が動作する
  • 削除前に確認メッセージを表示している
  • 登録・更新・削除後に一覧を再表示している
  • NULL項目に DBNull.Value を渡している
  • 入力チェックを行っている
  • Gitにcommitしている
  • Gitにpushしている

この章では、WindowsフォームアプリからOracle Databaseに対して、登録・更新・削除を行う方法を学習しました。

この章で学んだ主な内容は次の通りです。

  • CRUDは、Create、Read、Update、Deleteの基本操作である
  • INSERTUPDATEDELETE では ExecuteNonQuery を使う
  • 画面の入力値は、EmployeeEditModel に変換して扱うと整理しやすい
  • 空欄をDBのNULLにしたい場合は、C#側では null、DBへ渡すときは DBNull.Value を使う
  • DataGridViewの選択行から社員IDを取得できる
  • 選択した社員の詳細情報を入力欄に表示できる
  • 登録・更新・削除後は、一覧を再取得して画面を更新する
  • 削除処理では確認メッセージを表示する
  • Formは画面操作を担当し、RepositoryはDBアクセスを担当する
  • 初期データ復元SQLがあれば、演習後にデータを元に戻せる

次章では、研修全体のまとめと小さな総合演習 を行います。

コンソールアプリ、Webアプリ、Windowsフォームアプリ、Oracle Database接続を振り返り、現場で既存システムを読むために重要な観点を整理します。