Skip to content

第23章 WindowsフォームアプリからOracle Databaseを利用する

この章では、WindowsフォームアプリからOracle Databaseに接続し、DBから取得した社員一覧を DataGridView に表示する方法を学習します。

第22章では、サンプルデータを List<Employee> として作成し、DataGridView に表示しました。

_employees = CreateSampleEmployees();
DisplayEmployees(_employees);

この章では、サンプルデータではなく、Oracle Databaseの employees 表と departments 表からデータを取得します。

Oracle Database
EmployeeRepository
List<EmployeeListItem>
DataGridView

これまで学習した内容が、この章でつながります。

OracleConnection
→ Oracle Databaseに接続する
OracleCommand
→ SQL文を実行する
OracleDataReader
→ SELECT結果を1行ずつ読み取る
EmployeeListItem
→ 画面表示用の1行分のデータを表す
List<EmployeeListItem>
→ 社員一覧をまとめて扱う
DataGridView
→ 一覧を表形式で表示する

この章では、WindowsフォームアプリからDBを利用する基本として、次の機能を作成します。

社員一覧表示
社員名検索
部署ID検索
選択行の詳細表示

登録・更新・削除は、この章では扱いません。
まずは、デスクトップアプリからDBのデータを取得して画面表示する流れを理解します。


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

図23-1 WindowsフォームアプリとOracle Databaseの接続イメージ
図23-2 NuGetでOracle.ManagedDataAccess.Coreを追加する画面
図23-3 フォームにDataGridViewと検索欄を配置した画面
図23-4 Oracle DBから取得した社員一覧画面
図23-5 社員名検索の結果画面
図23-6 選択行の詳細表示画面
図23-7 Form、Repository、Oracle DBの役割分担

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

![WindowsフォームアプリとOracle Databaseの接続イメージ](images/23_winforms_oracle_overview.png)

画像ファイルは、images フォルダにまとめると管理しやすくなります。

CSharpText/
├─ 23_winforms_oracle_database.md
└─ images/
├─ 23_winforms_oracle_overview.png
├─ 23_nuget_oracle_package.png
├─ 23_form_layout.png
├─ 23_employee_list.png
└─ 23_employee_search.png

この章でできるようになること

Section titled “この章でできるようになること”

この章を終えると、次のことができるようになります。

  • WindowsフォームアプリからOracle Databaseに接続できる
  • Oracle.ManagedDataAccess.Core をWindowsフォームアプリに追加できる
  • EmployeeListItem クラスを作成できる
  • EmployeeRepository クラスを作成できる
  • employees 表と departments 表をJOINして社員一覧を取得できる
  • DBから取得したデータを List<EmployeeListItem> として扱える
  • DataGridView にDBのデータを表示できる
  • 社員名で検索できる
  • 部署IDで検索できる
  • 選択行の社員情報を取得できる
  • DB接続エラーが起きたときにメッセージを表示できる
  • Form、Repository、Modelの役割分担を説明できる

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

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

  • SQL*Plusで pingt ユーザーに接続できる
  • employees 表をSELECTできる
  • departments 表をSELECTできる
  • C#のコンソールアプリからOracle Databaseに接続できる
  • Windowsフォームアプリを作成できる
  • DataGridViewList<T> を表示できる
  • OracleConnectionOracleCommandOracleDataReader の基本を理解している
  • 第22章の内容をGitに提出済みである

この章では、Oracle Databaseから社員情報を取得し、Windowsフォームアプリに表示します。

画面には、次のような部品を配置します。

[一覧表示] [検索] [クリア] [選択行を表示]
社員名検索 [ ]
部署ID [ ]
件数:0件
+-------------------------------------------------------------+
| 社員ID | 社員名 | 部署名 | 入社日 | 給与 |
+-------------------------------------------------------------+
| 1001 | 山田二郎 | 総務 | 2001/04/01 | 500000 |
| 1002 | 佐藤昭夫 | 営業 | 2001/04/01 | 500000 |
+-------------------------------------------------------------+

このアプリでは、次の操作を行えます。

一覧表示
Oracle Databaseから社員一覧を取得してDataGridViewに表示する
社員名検索
入力された文字を含む社員を検索する
部署ID検索
指定された部署IDに所属する社員を検索する
選択行を表示
DataGridViewで選択した社員情報をMessageBoxに表示する

この章のアプリは、次の構成で作成します。

Form1
画面の操作を担当する
EmployeeRepository
Oracle Databaseから社員データを取得する
EmployeeListItem
DataGridViewに表示する1行分のデータを表す

役割を分けると、次のようになります。

クラス役割
Form1ボタンクリック、検索条件の取得、DataGridViewへの表示
EmployeeRepositoryOracle Databaseへの接続、SQL実行、データ取得
EmployeeListItem社員一覧に表示する1行分のデータ

フォームにSQL文を直接書くこともできますが、この章では書きません。

Form
→ 画面操作を担当する
Repository
→ DBアクセスを担当する

この分け方は、Webアプリ編で行ったControllerとRepositoryの分離と似ています。


23-3 Windowsフォームアプリを作成する

Section titled “23-3 Windowsフォームアプリを作成する”

Visual Studio 2022を起動し、次の手順でプロジェクトを作成します。

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

作成直後に空のフォームが表示されます。

まずは実行し、空のフォームが表示されることを確認してください。


23-4 Oracle接続用パッケージを追加する

Section titled “23-4 Oracle接続用パッケージを追加する”

WindowsフォームアプリからOracle Databaseに接続するために、NuGetパッケージを追加します。

使用するパッケージは、Webアプリ編やコンソールアプリ編と同じです。

Oracle.ManagedDataAccess.Core

Visual Studioで次の手順を行います。

1. ソリューションエクスプローラーでプロジェクト名を右クリックする
2. 「NuGet パッケージの管理」をクリックする
3. 「参照」タブを開く
4. 検索欄に Oracle.ManagedDataAccess.Core と入力する
5. Oracle.ManagedDataAccess.Core を選択する
6. 「インストール」をクリックする
7. 確認画面が出たら内容を確認して進める

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

using Oracle.ManagedDataAccess.Client;

23-5 EmployeeListItemクラスを作成する

Section titled “23-5 EmployeeListItemクラスを作成する”

まず、DataGridViewに表示する1行分のデータを表すクラスを作成します。

プロジェクトに EmployeeListItem.cs を追加します。

namespace Chapter23_WinFormsOracle
{
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; }
}
}

このクラスは、社員一覧画面に表示する情報を持ちます。

プロパティ意味
EmployeeId社員ID
EmployeeName社員名
DepartmentName部署名
HireDate入社日
Salary給与

Salarydecimal? にしています。

public decimal? Salary { get; set; }

これは、DBの salary がNULLになる可能性を考慮しているためです。


23-6 EmployeeRepositoryクラスを作成する

Section titled “23-6 EmployeeRepositoryクラスを作成する”

プロジェクトに EmployeeRepository.cs を追加します。

using Oracle.ManagedDataAccess.Client;
namespace Chapter23_WinFormsOracle
{
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>();
return employees;
}
}
}

このクラスは、Oracle Databaseから社員データを取得する役割を持ちます。


接続文字列は、Oracle Databaseに接続するための情報です。

private readonly string _connectionString =
"User Id=pingt;Password=oracle;Data Source=localhost:1521/XEPDB1;";

この章では、学習を優先してクラス内に直接書きます。

実務では、接続文字列は設定ファイルや環境変数などで管理することが多いです。


23-7 社員一覧をDBから取得する

Section titled “23-7 社員一覧をDBから取得する”

社員一覧では、employees 表と departments 表をJOINし、部署名も一緒に取得します。

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

EmployeeRepositoryGetEmployeeListItems メソッドを次のように作成します。

using Oracle.ManagedDataAccess.Client;
namespace Chapter23_WinFormsOracle
{
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 = CreateEmployeeListItem(reader);
employees.Add(employee);
}
}
}
return employees;
}
private EmployeeListItem CreateEmployeeListItem(OracleDataReader reader)
{
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"]);
return employee;
}
}
}

GetEmployeeListItems の流れは次の通りです。

1. 空の List<EmployeeListItem> を作成する
2. SQL文を用意する
3. OracleConnectionでDBに接続する
4. OracleCommandでSQL文を実行する
5. OracleDataReaderで1行ずつ読み取る
6. 1行分をEmployeeListItemに変換する
7. Listに追加する
8. 最後にListを返す

第17章や第19章で学習した流れと同じです。


23-8 フォームにコントロールを配置する

Section titled “23-8 フォームにコントロールを配置する”

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

コントロールNameText
ButtonbtnLoad一覧表示
ButtonbtnSearch検索
ButtonbtnClearクリア
ButtonbtnShowDetail選択行を表示
LabellblKeyword社員名検索
TextBoxtxtKeyword空欄
LabellblDepartmentId部署ID
TextBoxtxtDepartmentId空欄
LabellblCount件数:0件
DataGridViewdgvEmployeesなし

配置例:

[一覧表示] [検索] [クリア] [選択行を表示]
社員名検索 [ ]
部署ID [ ]
件数:0件
+-----------------------------------------------------+
| 社員ID | 社員名 | 部署名 | 入社日 | 給与 |
+-----------------------------------------------------+

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

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

コードで設定する場合は、Form1.cs に次のメソッドを作成します。

private void SetupDataGridView()
{
dgvEmployees.ReadOnly = true;
dgvEmployees.AllowUserToAddRows = false;
dgvEmployees.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dgvEmployees.MultiSelect = false;
dgvEmployees.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
}

コンストラクターから呼び出します。

public Form1()
{
InitializeComponent();
SetupDataGridView();
}

23-9 DBから取得した一覧をDataGridViewに表示する

Section titled “23-9 DBから取得した一覧をDataGridViewに表示する”

Form1.cs に、社員一覧を保持するフィールドを用意します。

namespace Chapter23_WinFormsOracle
{
public partial class Form1 : Form
{
private List<EmployeeListItem> _employees = new List<EmployeeListItem>();
public Form1()
{
InitializeComponent();
SetupDataGridView();
}
}
}

_employees には、DBから取得した全社員一覧を入れます。


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

private void DisplayEmployees(List<EmployeeListItem> employees)
{
dgvEmployees.DataSource = null;
dgvEmployees.DataSource = employees;
lblCount.Text = $"件数:{employees.Count}";
SetColumnHeaders();
}

DataGridViewの列見出しを日本語に変更します。

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 = "給与";
}
}

btnLoad をダブルクリックし、クリックイベントを作成します。

private void btnLoad_Click(object sender, EventArgs e)
{
try
{
EmployeeRepository repository = new EmployeeRepository();
_employees = repository.GetEmployeeListItems();
DisplayEmployees(_employees);
}
catch (Oracle.ManagedDataAccess.Client.OracleException ex)
{
MessageBox.Show("Oracle Database処理中にエラーが発生しました。\n" + ex.Message);
}
catch (Exception ex)
{
MessageBox.Show("予期しないエラーが発生しました。\n" + ex.Message);
}
}

実行し、一覧表示 ボタンをクリックしてください。

Oracle Databaseから取得した社員一覧がDataGridViewに表示されれば成功です。


Form1.cs の先頭に次の using を追加しておくと、OracleException を短く書けます。

using Oracle.ManagedDataAccess.Client;

その場合、catchは次のように書けます。

catch (OracleException ex)
{
MessageBox.Show("Oracle Database処理中にエラーが発生しました。\n" + ex.Message);
}

Repositoryに検索メソッドを追加する

Section titled “Repositoryに検索メソッドを追加する”

社員名で検索できるように、Repositoryにメソッドを追加します。

public List<EmployeeListItem> SearchEmployeeListItems(string? keyword, int? departmentId)
{
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
WHERE
(:keyword IS NULL OR e.employee_name LIKE :keyword)
AND (:departmentId IS NULL OR e.department_id = :departmentId)
ORDER BY
e.employee_id";
using (OracleConnection connection = new OracleConnection(_connectionString))
{
connection.Open();
using (OracleCommand command = new OracleCommand(sql, connection))
{
command.BindByName = true;
if (string.IsNullOrWhiteSpace(keyword))
{
command.Parameters.Add("keyword", OracleDbType.Varchar2).Value = DBNull.Value;
}
else
{
command.Parameters.Add("keyword", OracleDbType.Varchar2).Value = "%" + keyword + "%";
}
if (departmentId.HasValue)
{
command.Parameters.Add("departmentId", OracleDbType.Int32).Value = departmentId.Value;
}
else
{
command.Parameters.Add("departmentId", OracleDbType.Int32).Value = DBNull.Value;
}
using (OracleDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
EmployeeListItem employee = CreateEmployeeListItem(reader);
employees.Add(employee);
}
}
}
}
return employees;
}

SQLでは、検索条件を次のように書いています。

(:keyword IS NULL OR e.employee_name LIKE :keyword)

keyword がNULLの場合は、社員名条件を無視します。

社員名が入力されている場合は、部分一致検索を行います。

command.Parameters.Add("keyword", OracleDbType.Varchar2).Value = "%" + keyword + "%";

部署IDも同じ考え方です。

(:departmentId IS NULL OR e.department_id = :departmentId)

部署IDが指定されている場合だけ、部署IDで絞り込みます。


23-11 検索ボタンの処理を作成する

Section titled “23-11 検索ボタンの処理を作成する”

btnSearch のクリックイベントを作成します。

private void btnSearch_Click(object sender, EventArgs e)
{
string keyword = txtKeyword.Text.Trim();
string departmentIdText = txtDepartmentId.Text.Trim();
int? departmentId = null;
if (!string.IsNullOrWhiteSpace(departmentIdText))
{
if (!int.TryParse(departmentIdText, out int parsedDepartmentId))
{
MessageBox.Show("部署IDは整数で入力してください。");
return;
}
departmentId = parsedDepartmentId;
}
try
{
EmployeeRepository repository = new EmployeeRepository();
List<EmployeeListItem> results = repository.SearchEmployeeListItems(keyword, departmentId);
DisplayEmployees(results);
if (results.Count == 0)
{
MessageBox.Show("該当する社員は見つかりませんでした。");
}
}
catch (Oracle.ManagedDataAccess.Client.OracleException ex)
{
MessageBox.Show("Oracle Database処理中にエラーが発生しました。\n" + ex.Message);
}
catch (Exception ex)
{
MessageBox.Show("予期しないエラーが発生しました。\n" + ex.Message);
}
}

このコードでは、部署IDが入力されている場合だけ int に変換します。

空欄の場合は、departmentIdnull のままです。

int? departmentId = null;

btnClear のクリックイベントを作成します。

private void btnClear_Click(object sender, EventArgs e)
{
txtKeyword.Clear();
txtDepartmentId.Clear();
DisplayEmployees(_employees);
}

検索後に全件表示へ戻すため、_employees に保持している全件データを再表示します。


検索ボタンでは、DBへ再度問い合わせています。

repository.SearchEmployeeListItems(keyword, departmentId);

一方、クリアボタンでは、すでに取得済みの _employees を表示しています。

DisplayEmployees(_employees);

必要に応じて、クリア時にもDBから再取得しても構いません。

_employees = repository.GetEmployeeListItems();
DisplayEmployees(_employees);

この章では、まず流れを分かりやすくするために、保持済みの全件データを再表示します。


第22章と同じように、選択行の DataBoundItem から EmployeeListItem を取得します。

btnShowDetail のクリックイベントを作成します。

private void btnShowDetail_Click(object sender, EventArgs e)
{
if (dgvEmployees.CurrentRow == null)
{
MessageBox.Show("社員を選択してください。");
return;
}
EmployeeListItem? employee =
dgvEmployees.CurrentRow.DataBoundItem as EmployeeListItem;
if (employee == null)
{
MessageBox.Show("社員情報を取得できませんでした。");
return;
}
string salaryText = employee.Salary.HasValue
? $"{employee.Salary.Value}"
: "未設定";
string message =
$"社員ID:{employee.EmployeeId}\n" +
$"社員名:{employee.EmployeeName}\n" +
$"部署名:{employee.DepartmentName}\n" +
$"入社日:{employee.HireDate.ToString("yyyy/MM/dd")}\n" +
$"給与:{salaryText}";
MessageBox.Show(message);
}

DataGridView に設定している元データは、List<EmployeeListItem> です。

dgvEmployees.DataSource = employees;

そのため、選択行の DataBoundItemEmployeeListItem として取り出せます。

EmployeeListItem? employee =
dgvEmployees.CurrentRow.DataBoundItem as EmployeeListItem;

ここまでの Form1.cs の主要部分は、次のようになります。

using Oracle.ManagedDataAccess.Client;
namespace Chapter23_WinFormsOracle
{
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;
}
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 = "給与";
}
}
private void btnLoad_Click(object sender, EventArgs e)
{
try
{
EmployeeRepository repository = new EmployeeRepository();
_employees = repository.GetEmployeeListItems();
DisplayEmployees(_employees);
}
catch (OracleException ex)
{
MessageBox.Show("Oracle Database処理中にエラーが発生しました。\n" + ex.Message);
}
catch (Exception ex)
{
MessageBox.Show("予期しないエラーが発生しました。\n" + ex.Message);
}
}
private void btnSearch_Click(object sender, EventArgs e)
{
string keyword = txtKeyword.Text.Trim();
string departmentIdText = txtDepartmentId.Text.Trim();
int? departmentId = null;
if (!string.IsNullOrWhiteSpace(departmentIdText))
{
if (!int.TryParse(departmentIdText, out int parsedDepartmentId))
{
MessageBox.Show("部署IDは整数で入力してください。");
return;
}
departmentId = parsedDepartmentId;
}
try
{
EmployeeRepository repository = new EmployeeRepository();
List<EmployeeListItem> results =
repository.SearchEmployeeListItems(keyword, departmentId);
DisplayEmployees(results);
if (results.Count == 0)
{
MessageBox.Show("該当する社員は見つかりませんでした。");
}
}
catch (OracleException ex)
{
MessageBox.Show("Oracle Database処理中にエラーが発生しました。\n" + ex.Message);
}
catch (Exception ex)
{
MessageBox.Show("予期しないエラーが発生しました。\n" + ex.Message);
}
}
private void btnClear_Click(object sender, EventArgs e)
{
txtKeyword.Clear();
txtDepartmentId.Clear();
DisplayEmployees(_employees);
}
private void btnShowDetail_Click(object sender, EventArgs e)
{
if (dgvEmployees.CurrentRow == null)
{
MessageBox.Show("社員を選択してください。");
return;
}
EmployeeListItem? employee =
dgvEmployees.CurrentRow.DataBoundItem as EmployeeListItem;
if (employee == null)
{
MessageBox.Show("社員情報を取得できませんでした。");
return;
}
string salaryText = employee.Salary.HasValue
? $"{employee.Salary.Value}"
: "未設定";
string message =
$"社員ID:{employee.EmployeeId}\n" +
$"社員名:{employee.EmployeeName}\n" +
$"部署名:{employee.DepartmentName}\n" +
$"入社日:{employee.HireDate.ToString("yyyy/MM/dd")}\n" +
$"給与:{salaryText}";
MessageBox.Show(message);
}
}
}

1. 利用者が「一覧表示」ボタンをクリックする
2. btnLoad_Click が実行される
3. EmployeeRepository が作成される
4. GetEmployeeListItems が呼ばれる
5. Oracle Databaseへ接続する
6. SELECT文を実行する
7. OracleDataReaderで1行ずつ読み取る
8. EmployeeListItemに変換する
9. List<EmployeeListItem>としてFormに返す
10. DataGridViewに表示する

1. 利用者が社員名や部署IDを入力する
2. 「検索」ボタンをクリックする
3. btnSearch_Click が実行される
4. 入力値を取得する
5. 部署IDが入力されていれば整数に変換する
6. Repositoryの検索メソッドを呼び出す
7. SQLパラメーターを使ってSELECTする
8. 結果をDataGridViewに表示する

1. 利用者がDataGridViewの行を選択する
2. 「選択行を表示」ボタンをクリックする
3. CurrentRowから選択行を取得する
4. DataBoundItemからEmployeeListItemを取得する
5. MessageBoxに社員情報を表示する

第19章では、MVCアプリからOracle Databaseに接続しました。

EmployeesController
EmployeeRepository
Oracle Database
View

この章では、Windowsフォームアプリから同じようにOracle Databaseに接続しています。

Form1
EmployeeRepository
Oracle Database
DataGridView

違うのは、表示する場所です。

種類表示先
WebアプリView、HTML、ブラウザー
WindowsフォームアプリForm、DataGridView

一方で、DBアクセス部分の考え方は共通しています。

接続する
SQLを実行する
DataReaderで読み取る
オブジェクトに変換する
List<T>で返す

つまり、C#アプリでは、アプリの種類が違っても、DBアクセスの基本的な流れは共通しています。


つまずき原因対応
OracleConnection が見つからないNuGetパッケージが入っていないOracle.ManagedDataAccess.Core を追加する
OracleException が見つからないusing が不足しているusing Oracle.ManagedDataAccess.Client; を追加する
DBに接続できないOracle Databaseが起動していないSQL*Plusで接続確認する
一覧が表示されないDataSource を設定していないDisplayEmployees を確認する
DataGridViewが空になるSQL結果が0件SQL*Plusで同じSQLを実行する
列見出しが英語のままSetColumnHeaders を呼んでいないDisplayEmployees 内で呼ぶ
検索しても全件出るパラメーターがNULL扱いになっている入力値とSQL条件を確認する
部署ID検索でエラーになる数字以外を入力しているint.TryParse で確認する
給与NULLでエラーになるDBNull.Value を確認していない変換前にNULL確認する
選択行を取得できないDataGridViewで行を選択していないCurrentRow == null を確認する
DataBoundItem がnullになるDataSourceが正しくないList<EmployeeListItem> を設定しているか確認する

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

  • WindowsフォームアプリからOracle Databaseに接続できる
  • Oracle.ManagedDataAccess.Core を追加できる
  • EmployeeListItem の役割を説明できる
  • EmployeeRepository の役割を説明できる
  • employeesdepartments をJOINして一覧データを取得できる
  • OracleDataReader から EmployeeListItem を作成できる
  • List<EmployeeListItem> をDataGridViewに表示できる
  • DataGridViewの列見出しを日本語に変更できる
  • 社員名検索を実装できる
  • 部署ID検索を実装できる
  • SQLパラメーターを使って検索条件を渡せる
  • 選択行の DataBoundItem から社員情報を取得できる
  • DB接続エラーが起きたときの確認ポイントを説明できる

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

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

  1. WindowsフォームアプリからDBを利用する場合、どのクラスがDBアクセスを担当していますか。
  2. Form1 にSQL文を直接書かない理由は何ですか。
  3. EmployeeListItem は何を表すクラスですか。
  4. DataGridView.DataSource には何を設定していますか。
  5. DBのNULLをC#で扱うとき、何を確認しますか。
  6. 社員名検索でSQLパラメーターを使う理由は何ですか。
  7. CurrentRowDataBoundItem はそれぞれ何を表していますか。
  8. Webアプリ編とWindowsフォームアプリ編で、DBアクセス処理の共通点は何ですか。

この章の演習課題に取り組みます。

制限時間は 100分 です。

時間内にすべて完成しなくても構いません。
できたところまでを保存し、Gitに提出してください。


課題23-1 Windowsフォームアプリを作成する

Section titled “課題23-1 Windowsフォームアプリを作成する”

Windowsフォームアプリのプロジェクトを作成してください。

条件:

  • プロジェクト名は Chapter23_WinFormsOracle とする
  • フレームワークは .NET 8.0 を選択する
  • 初期状態で実行し、フォームが表示されることを確認する

課題23-2 Oracle接続用パッケージを追加する

Section titled “課題23-2 Oracle接続用パッケージを追加する”

NuGetで Oracle.ManagedDataAccess.Core を追加してください。

条件:

  • プロジェクトにパッケージを追加する
  • using Oracle.ManagedDataAccess.Client; を使える状態にする

課題23-3 EmployeeListItemクラスを作成する

Section titled “課題23-3 EmployeeListItemクラスを作成する”

社員一覧表示用の EmployeeListItem クラスを作成してください。

プロパティ:

プロパティ名
EmployeeIdint
EmployeeNamestring
DepartmentNamestring
HireDateDateTime
Salarydecimal?

条件:

  • EmployeeListItem.cs を作成する
  • Salarydecimal? にする
  • 文字列プロパティには初期値 "" を設定する

課題23-4 EmployeeRepositoryを作成する

Section titled “課題23-4 EmployeeRepositoryを作成する”

Oracle Databaseから社員一覧を取得する EmployeeRepository クラスを作成してください。

条件:

  • EmployeeRepository.cs を作成する
  • 接続文字列をフィールドとして定義する
  • GetEmployeeListItems メソッドを作成する
  • employeesdepartments をJOINする
  • SELECT結果を EmployeeListItem に変換する
  • List<EmployeeListItem> として返す

課題23-5 DataGridViewに社員一覧を表示する

Section titled “課題23-5 DataGridViewに社員一覧を表示する”

DBから取得した社員一覧をDataGridViewに表示してください。

条件:

  • フォームに dgvEmployees を配置する
  • btnLoad を配置する
  • lblCount を配置する
  • btnLoad_Click でRepositoryを呼び出す
  • DisplayEmployees メソッドでDataGridViewに表示する
  • 件数を表示する

課題23-6 列見出しを日本語にする

Section titled “課題23-6 列見出しを日本語にする”

DataGridViewの列見出しを日本語に変更してください。

条件:

  • EmployeeId社員ID にする
  • EmployeeName社員名 にする
  • DepartmentName部署名 にする
  • HireDate入社日 にする
  • Salary給与 にする

課題23-7 社員名検索を作成する

Section titled “課題23-7 社員名検索を作成する”

社員名で部分一致検索できるようにしてください。

条件:

  • txtKeyword を追加する
  • btnSearch を追加する
  • Repositoryに検索メソッドを追加する
  • SQLで LIKE :keyword を使う
  • SQLパラメーターを使う
  • 検索結果をDataGridViewに表示する

課題23-8 部署ID検索を追加する

Section titled “課題23-8 部署ID検索を追加する”

部署IDで検索できるようにしてください。

条件:

  • txtDepartmentId を追加する
  • 部署IDが入力されている場合は整数チェックする
  • Repositoryに部署ID条件を追加する
  • 社員名と部署IDの両方で検索できるようにする

課題23-9 クリアボタンを作成する

Section titled “課題23-9 クリアボタンを作成する”

検索条件をクリアし、全件表示に戻してください。

条件:

  • btnClear を追加する
  • txtKeyword.Clear() を使う
  • txtDepartmentId.Clear() を使う
  • 全件一覧をDataGridViewに表示する

課題23-10 選択行の社員情報を表示する

Section titled “課題23-10 選択行の社員情報を表示する”

DataGridViewで選択した社員情報を、メッセージボックスで表示してください。

条件:

  • btnShowDetail を追加する
  • CurrentRow を確認する
  • DataBoundItem から EmployeeListItem を取得する
  • 何も選択されていない場合はメッセージを表示する

課題23-11 SQL*Plusで同じSQLを確認する

Section titled “課題23-11 SQL*Plusで同じSQLを確認する”

Windowsフォームアプリで使用しているSQLを、SQL*Plusでも実行してください。

条件:

  • 社員一覧用SQLをSQL*Plusで実行する
  • 社員名検索用SQLをSQL*Plusで実行する
  • 部署ID検索用SQLをSQL*Plusで実行する
  • アプリ画面の結果と一致することを確認する

課題が終わったら、できたところまでをGitに提出します。

Terminal window
git status
git add .
git commit -m "Chapter23 WinFormsからOracle Databaseを利用"
git push

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


  • Windowsフォームアプリを作成できている
  • Oracle.ManagedDataAccess.Core を追加している
  • EmployeeListItem クラスを作成している
  • EmployeeRepository クラスを作成している
  • employeesdepartments をJOINして取得している
  • DBのNULLを DBNull.Value で確認している
  • List<EmployeeListItem> をDataGridViewに表示している
  • DataGridViewの列見出しを日本語にしている
  • 社員名検索ができている
  • 部署ID検索ができている
  • SQLパラメーターを使っている
  • 選択行の社員情報を表示できている
  • DB接続エラー時にメッセージを表示している
  • インデントが整っている
  • Gitにcommitしている
  • Gitにpushしている

この章では、WindowsフォームアプリからOracle Databaseを利用する方法を学習しました。

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

  • WindowsフォームアプリからOracle Databaseに接続できる
  • Oracle接続には Oracle.ManagedDataAccess.Core を利用する
  • DBアクセス処理は EmployeeRepository に分けると見通しがよくなる
  • employeesdepartments をJOINして、社員一覧に部署名を表示できる
  • DBから取得した1行分のデータを EmployeeListItem に変換できる
  • 複数行の結果を List<EmployeeListItem> として扱える
  • DataGridView.DataSourceList<EmployeeListItem> を設定すると、一覧表示できる
  • DataGridViewの列見出しを日本語に変更できる
  • 社員名や部署IDで検索できる
  • 検索条件はSQLパラメーターで渡す
  • DBのNULLは DBNull.Value として確認する必要がある
  • 選択行の DataBoundItem から、元の EmployeeListItem を取得できる
  • Webアプリとデスクトップアプリでは表示方法は違うが、DBアクセスの基本的な流れは共通している

次章では、Windowsフォームアプリで登録・更新・削除の流れを体験する ことを学習します。

ただし、Webアプリ編と同じく、既存データを壊さないために9000番台の社員IDを研修用データとして扱い、INSERT / UPDATE / DELETE の基本的な流れを確認します。