Skip to content

第20章 Webアプリで登録・更新・削除の流れを体験する

この章では、ASP.NET Core MVCアプリからOracle Databaseに対して、登録・更新・削除を行う基本的な流れを学習します。

第19章では、Oracle Databaseから社員情報を取得し、Web画面に表示しました。

一覧表示
詳細表示
社員名検索
部署ID検索

この章では、さらに次の操作を追加します。

登録
更新
削除

ただし、この章の目的は、本格的な業務アプリを完成させることではありません。

目的は、次の流れを体験することです。

フォームを表示する
利用者が値を入力する
Controllerが入力値を受け取る
RepositoryがINSERT / UPDATE / DELETEを実行する
一覧画面に戻る

この章では、employees 表を使って登録・更新・削除を行います。

ただし、既存のSQL研修用データを誤って変更しないように、次のルールを設けます。

登録する社員IDは9000番台にする
更新・削除は9000番台の社員のみ対象にする

例:

9001
9002
9003

このようにすることで、既存の社員データを残したまま、Webアプリからの更新操作を練習できます。

重要

この章ではDBのデータを変更します。 操作する前に、必ず研修用環境であることを確認してください。 本番環境や共有環境では、勝手にINSERT / UPDATE / DELETEを実行してはいけません。


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

図20-1 CRUD処理の全体像
図20-2 登録画面
図20-3 登録後に一覧へ戻る流れ
図20-4 更新画面
図20-5 削除確認画面
図20-6 Controller、Repository、Oracle DBの役割分担

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

![CRUD処理の全体像](images/20_crud_overview.png)

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

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

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

  • CRUDとは何かを説明できる
  • GETとPOSTの違いをおおまかに説明できる
  • MVCで登録フォームを表示できる
  • フォームから送信された値をControllerで受け取れる
  • INSERT 文を実行してDBにデータを追加できる
  • UPDATE 文を実行してDBのデータを更新できる
  • DELETE 文を実行してDBのデータを削除できる
  • 入力値を簡単に検証できる
  • ModelState の基本的な使い方を理解できる
  • RedirectToAction を使って処理後に一覧画面へ戻れる
  • TempData を使って一時的なメッセージを表示できる
  • 更新・削除対象を研修用データに限定する理由を説明できる

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

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

  • 第19章のMVCアプリからOracle Databaseに接続できる
  • 社員一覧画面を表示できる
  • 社員詳細画面を表示できる
  • EmployeeRepository の役割を説明できる
  • INSERTUPDATEDELETE のSQLをおおまかに読める
  • SQLパラメーターを使う理由を説明できる
  • Gitに前章の内容を提出済みである

CRUDとは、データを扱う基本的な4つの操作です。

操作意味SQL
Create登録INSERT
Read参照SELECT
Update更新UPDATE
Delete削除DELETE

第19章では、主にReadを扱いました。

社員一覧を表示する
社員詳細を表示する
検索する

この章では、Create、Update、Deleteを追加します。

社員を登録する
社員情報を更新する
社員を削除する

GETは、主に画面を表示したり、検索条件を送ったりするときに使います。

例:

/Employees
/Employees/Details/1001
/Employees?keyword=山

GETは、URLに情報が表れやすいのが特徴です。


POSTは、登録・更新・削除など、データを変更する処理でよく使います。

登録フォームを送信する
更新フォームを送信する
削除確認フォームを送信する

この章では、次のように使い分けます。

処理HTTPメソッド役割
登録画面表示GET入力フォームを表示する
登録実行POSTDBにINSERTする
更新画面表示GET既存データをフォームに表示する
更新実行POSTDBにUPDATEする
削除確認画面表示GET削除前に確認する
削除実行POSTDBからDELETEする

登録画面と更新画面では、利用者が入力するためのModelを使います。

Models フォルダに EmployeeEditModel.cs を作成します。

namespace Chapter20_MvcCrud.Models
{
public class EmployeeEditModel
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string? Yomi { get; set; }
public int JobId { get; set; } = 1004;
public int? ManagerId { get; set; }
public DateTime HireDate { get; set; } = DateTime.Today;
public decimal? Salary { get; set; }
public decimal? Commission { get; set; }
public int DepartmentId { get; set; } = 1;
}
}

EmployeeEditModel は、登録・更新フォームで使うModelです。

第19章では、一覧用に EmployeeListItem、詳細用に EmployeeDetail を作成しました。

この章では、入力用に EmployeeEditModel を使います。

EmployeeListItem
一覧表示用
EmployeeDetail
詳細表示用
EmployeeEditModel
登録・更新フォーム用

画面ごとに必要なデータの形が異なるため、Modelを分けています。


20-4 Repositoryに登録処理を追加する

Section titled “20-4 Repositoryに登録処理を追加する”

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

主に次のSQLで使います。

INSERT
UPDATE
DELETE

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

OracleDataReader reader = command.ExecuteReader();

登録・更新・削除では、結果表を読み取る必要がないため、ExecuteNonQuery を使います。

command.ExecuteNonQuery();

EmployeesController に、登録画面表示用の Create Actionを追加します。

[HttpGet]
public IActionResult Create()
{
EmployeeEditModel model = new EmployeeEditModel
{
EmployeeId = 9001,
HireDate = DateTime.Today,
JobId = 1004,
DepartmentId = 1
};
return View(model);
}

[HttpGet] は、GETリクエストで呼ばれるActionであることを表します。

このActionは、登録フォームを表示するためのものです。


Views/Employees フォルダに Create.cshtml を作成します。

@model Chapter20_MvcCrud.Models.EmployeeEditModel
@{
ViewData["Title"] = "社員登録";
}
<h1>社員登録</h1>
<div asp-validation-summary="All" class="text-danger"></div>
<form asp-controller="Employees" asp-action="Create" method="post">
<div class="mb-3">
<label asp-for="EmployeeId" class="form-label">社員ID</label>
<input asp-for="EmployeeId" class="form-control" />
<div class="form-text">研修では9000番台を使用します。</div>
</div>
<div class="mb-3">
<label asp-for="EmployeeName" class="form-label">社員名</label>
<input asp-for="EmployeeName" class="form-control" />
</div>
<div class="mb-3">
<label asp-for="Yomi" class="form-label">よみがな</label>
<input asp-for="Yomi" class="form-control" />
</div>
<div class="mb-3">
<label asp-for="JobId" class="form-label">職種ID</label>
<input asp-for="JobId" class="form-control" />
</div>
<div class="mb-3">
<label asp-for="ManagerId" class="form-label">上司ID</label>
<input asp-for="ManagerId" class="form-control" />
</div>
<div class="mb-3">
<label asp-for="HireDate" class="form-label">入社日</label>
<input asp-for="HireDate" type="date" class="form-control" />
</div>
<div class="mb-3">
<label asp-for="Salary" class="form-label">給与</label>
<input asp-for="Salary" class="form-control" />
</div>
<div class="mb-3">
<label asp-for="Commission" class="form-label">歩合</label>
<input asp-for="Commission" class="form-control" />
</div>
<div class="mb-3">
<label asp-for="DepartmentId" class="form-label">部署ID</label>
<input asp-for="DepartmentId" class="form-control" />
<div class="form-text">1〜5の部署IDを指定します。</div>
</div>
<button type="submit" class="btn btn-primary">登録</button>
<a asp-controller="Employees" asp-action="Index" class="btn btn-secondary">戻る</a>
</form>

asp-for は、Modelのプロパティと入力欄を対応させるための書き方です。

<input asp-for="EmployeeName" class="form-control" />

これは、EmployeeEditModelEmployeeName プロパティに対応する入力欄です。

フォーム送信時には、入力された値がControllerの引数に自動的に入ります。


EmployeesController に、登録実行用の Create Actionを追加します。

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(EmployeeEditModel model)
{
ValidateEmployeeEditModel(model);
if (!ModelState.IsValid)
{
return View(model);
}
try
{
EmployeeRepository repository = new EmployeeRepository();
repository.Insert(model);
TempData["Message"] = "社員を登録しました。";
return RedirectToAction(nameof(Index));
}
catch (OracleException ex)
{
ModelState.AddModelError("", "Oracle Database処理中にエラーが発生しました。");
ModelState.AddModelError("", ex.Message);
return View(model);
}
catch (Exception ex)
{
ModelState.AddModelError("", "予期しないエラーが発生しました。");
ModelState.AddModelError("", ex.Message);
return View(model);
}
}

ModelState は、入力値の状態を管理する仕組みです。

入力値に問題がある場合は、次のようにエラーを追加できます。

ModelState.AddModelError("EmployeeName", "社員名を入力してください。");

エラーがあるかどうかは、次のように確認できます。

if (!ModelState.IsValid)
{
return View(model);
}

エラーがある場合、登録処理は行わず、入力画面を再表示します。


EmployeesController に、簡単な入力チェック用メソッドを作成します。

private void ValidateEmployeeEditModel(EmployeeEditModel model)
{
if (model.EmployeeId < 9000 || model.EmployeeId > 9999)
{
ModelState.AddModelError("EmployeeId", "研修では社員IDに9000〜9999を指定してください。");
}
if (string.IsNullOrWhiteSpace(model.EmployeeName))
{
ModelState.AddModelError("EmployeeName", "社員名を入力してください。");
}
if (model.JobId <= 0)
{
ModelState.AddModelError("JobId", "職種IDを入力してください。");
}
if (model.DepartmentId < 1 || model.DepartmentId > 5)
{
ModelState.AddModelError("DepartmentId", "部署IDは1〜5で入力してください。");
}
if (model.Salary.HasValue && model.Salary.Value < 0)
{
ModelState.AddModelError("Salary", "給与にマイナス値は指定できません。");
}
if (model.Commission.HasValue && model.Commission.Value < 0)
{
ModelState.AddModelError("Commission", "歩合にマイナス値は指定できません。");
}
}

本格的にはDataAnnotationsを使った入力チェックもありますが、この章では処理の流れを見やすくするため、Controller内で簡単にチェックします。


TempData は、次のリクエストまで一時的に値を保持する仕組みです。

TempData["Message"] = "社員を登録しました。";

登録後は一覧画面へリダイレクトします。

return RedirectToAction(nameof(Index));

リダイレクト後の一覧画面で、メッセージを表示できます。


Index.cshtmlにメッセージを表示する

Section titled “Index.cshtmlにメッセージを表示する”

Views/Employees/Index.cshtml の上部に、次のコードを追加します。

@if (TempData["Message"] != null)
{
<div class="alert alert-success">
@TempData["Message"]
</div>
}

これで、登録後に一覧画面へ戻ったとき、次のようなメッセージが表示されます。

社員を登録しました。

20-7 一覧画面に登録リンクを追加する

Section titled “20-7 一覧画面に登録リンクを追加する”

Index.cshtml の見出しの下などに、登録画面へのリンクを追加します。

<p>
<a asp-controller="Employees" asp-action="Create" class="btn btn-primary">新規登録</a>
</p>

これで、一覧画面から登録画面に移動できます。


更新画面では、まず既存の社員データを取得してフォームに表示します。

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())
{
return new EmployeeEditModel
{
EmployeeId = Convert.ToInt32(reader["employee_id"]),
EmployeeName = reader["employee_name"].ToString() ?? "",
Yomi = reader["yomi"] == DBNull.Value ? null : reader["yomi"].ToString(),
JobId = Convert.ToInt32(reader["job_id"]),
ManagerId = reader["manager_id"] == DBNull.Value
? null
: Convert.ToInt32(reader["manager_id"]),
HireDate = Convert.ToDateTime(reader["hiredate"]),
Salary = reader["salary"] == DBNull.Value
? null
: Convert.ToDecimal(reader["salary"]),
Commission = reader["commission"] == DBNull.Value
? null
: Convert.ToDecimal(reader["commission"]),
DepartmentId = Convert.ToInt32(reader["department_id"])
};
}
}
}
}
return null;
}

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
AND employee_id >= 9000";
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();
}
}
}

WHERE employee_id >= 9000 を入れているため、既存の1000番台データは更新されません。


EmployeesController に、更新画面表示用のActionを追加します。

[HttpGet]
public IActionResult Edit(int id)
{
EmployeeRepository repository = new EmployeeRepository();
EmployeeEditModel? employee = repository.FindEditById(id);
if (employee == null)
{
return NotFound();
}
return View(employee);
}

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(EmployeeEditModel model)
{
ValidateEmployeeEditModel(model);
if (!ModelState.IsValid)
{
return View(model);
}
try
{
EmployeeRepository repository = new EmployeeRepository();
int count = repository.Update(model);
if (count == 0)
{
ModelState.AddModelError("", "更新対象が見つかりません。研修用ID 9000番台のみ更新できます。");
return View(model);
}
TempData["Message"] = "社員情報を更新しました。";
return RedirectToAction(nameof(Index));
}
catch (OracleException ex)
{
ModelState.AddModelError("", "Oracle Database処理中にエラーが発生しました。");
ModelState.AddModelError("", ex.Message);
return View(model);
}
}

Views/Employees フォルダに Edit.cshtml を作成します。

Create.cshtml とほぼ同じですが、社員IDは変更させないようにします。

@model Chapter20_MvcCrud.Models.EmployeeEditModel
@{
ViewData["Title"] = "社員情報更新";
}
<h1>社員情報更新</h1>
<div asp-validation-summary="All" class="text-danger"></div>
<form asp-controller="Employees" asp-action="Edit" method="post">
<input type="hidden" asp-for="EmployeeId" />
<div class="mb-3">
<label class="form-label">社員ID</label>
<input value="@Model.EmployeeId" class="form-control" readonly />
</div>
<div class="mb-3">
<label asp-for="EmployeeName" class="form-label">社員名</label>
<input asp-for="EmployeeName" class="form-control" />
</div>
<div class="mb-3">
<label asp-for="Yomi" class="form-label">よみがな</label>
<input asp-for="Yomi" class="form-control" />
</div>
<div class="mb-3">
<label asp-for="JobId" class="form-label">職種ID</label>
<input asp-for="JobId" class="form-control" />
</div>
<div class="mb-3">
<label asp-for="ManagerId" class="form-label">上司ID</label>
<input asp-for="ManagerId" class="form-control" />
</div>
<div class="mb-3">
<label asp-for="HireDate" class="form-label">入社日</label>
<input asp-for="HireDate" type="date" class="form-control" />
</div>
<div class="mb-3">
<label asp-for="Salary" class="form-label">給与</label>
<input asp-for="Salary" class="form-control" />
</div>
<div class="mb-3">
<label asp-for="Commission" class="form-label">歩合</label>
<input asp-for="Commission" class="form-control" />
</div>
<div class="mb-3">
<label asp-for="DepartmentId" class="form-label">部署ID</label>
<input asp-for="DepartmentId" class="form-control" />
</div>
<button type="submit" class="btn btn-primary">更新</button>
<a asp-controller="Employees" asp-action="Index" class="btn btn-secondary">戻る</a>
</form>

20-9 一覧画面に更新リンクを追加する

Section titled “20-9 一覧画面に更新リンクを追加する”

Index.cshtml の一覧表に更新リンクを追加します。

<td>
<a asp-controller="Employees"
asp-action="Details"
asp-route-id="@employee.EmployeeId">詳細</a>
|
<a asp-controller="Employees"
asp-action="Edit"
asp-route-id="@employee.EmployeeId">更新</a>
</td>

ただし、この章では9000番台のみ更新対象です。

既存データの更新リンクを押した場合、画面は表示されても、実際の更新時にエラー扱いになります。

発展として、9000番台のみ更新リンクを表示するようにしてもよいです。

@if (employee.EmployeeId >= 9000)
{
<a asp-controller="Employees"
asp-action="Edit"
asp-route-id="@employee.EmployeeId">更新</a>
}

EmployeeRepository に、削除用メソッドを追加します。

public int Delete(int employeeId)
{
string sql = @"
DELETE FROM employees
WHERE employee_id = :employeeId
AND employee_id >= 9000";
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();
}
}
}

このメソッドも、9000番台の社員だけを削除対象にしています。


EmployeesController に、削除確認画面を表示するActionを追加します。

[HttpGet]
public IActionResult Delete(int id)
{
EmployeeRepository repository = new EmployeeRepository();
EmployeeDetail? employee = repository.FindDetailById(id);
if (employee == null)
{
return NotFound();
}
return View(employee);
}

POSTで削除を実行します。

[HttpPost]
[ValidateAntiForgeryToken]
[ActionName("Delete")]
public IActionResult DeleteConfirmed(int id)
{
try
{
EmployeeRepository repository = new EmployeeRepository();
int count = repository.Delete(id);
if (count == 0)
{
TempData["Message"] = "削除対象が見つかりません。研修用ID 9000番台のみ削除できます。";
}
else
{
TempData["Message"] = "社員情報を削除しました。";
}
return RedirectToAction(nameof(Index));
}
catch (OracleException ex)
{
TempData["Message"] = "Oracle Database処理中にエラーが発生しました。" + ex.Message;
return RedirectToAction(nameof(Index));
}
}

Views/Employees フォルダに Delete.cshtml を作成します。

@model Chapter20_MvcCrud.Models.EmployeeDetail
@{
ViewData["Title"] = "社員削除";
}
<h1>社員削除</h1>
<div class="alert alert-warning">
次の社員を削除します。よろしいですか?
</div>
<table class="table">
<tr>
<th>社員ID</th>
<td>@Model.EmployeeId</td>
</tr>
<tr>
<th>社員名</th>
<td>@Model.EmployeeName</td>
</tr>
<tr>
<th>部署名</th>
<td>@Model.DepartmentName</td>
</tr>
</table>
@if (Model.EmployeeId < 9000)
{
<div class="alert alert-danger">
既存のSQL研修データは削除できません。削除できるのは9000番台の研修用データのみです。
</div>
}
else
{
<form asp-controller="Employees" asp-action="Delete" method="post">
<input type="hidden" name="id" value="@Model.EmployeeId" />
<button type="submit" class="btn btn-danger">削除</button>
<a asp-controller="Employees" asp-action="Index" class="btn btn-secondary">戻る</a>
</form>
}

20-11 一覧画面に削除リンクを追加する

Section titled “20-11 一覧画面に削除リンクを追加する”

Index.cshtml の一覧表に削除リンクを追加します。

<td>
<a asp-controller="Employees"
asp-action="Details"
asp-route-id="@employee.EmployeeId">詳細</a>
@if (employee.EmployeeId >= 9000)
{
@: |
<a asp-controller="Employees"
asp-action="Edit"
asp-route-id="@employee.EmployeeId">更新</a>
@: |
<a asp-controller="Employees"
asp-action="Delete"
asp-route-id="@employee.EmployeeId">削除</a>
}
</td>

このようにすると、9000番台の研修用データだけに更新・削除リンクを表示できます。


1. 一覧画面で「新規登録」をクリックする
2. GET /Employees/Create が呼ばれる
3. Create.cshtml が表示される
4. 入力して登録ボタンを押す
5. POST /Employees/Create が呼ばれる
6. Controllerが入力値を受け取る
7. 入力チェックを行う
8. Repository.Insert が呼ばれる
9. INSERT文が実行される
10. 一覧画面へリダイレクトする

1. 一覧画面で「更新」をクリックする
2. GET /Employees/Edit/9001 が呼ばれる
3. Repository.FindEditById で既存データを取得する
4. Edit.cshtml に既存値が表示される
5. 修正して更新ボタンを押す
6. POST /Employees/Edit が呼ばれる
7. Repository.Update が呼ばれる
8. UPDATE文が実行される
9. 一覧画面へリダイレクトする

1. 一覧画面で「削除」をクリックする
2. GET /Employees/Delete/9001 が呼ばれる
3. Delete.cshtml で削除確認する
4. 削除ボタンを押す
5. POST /Employees/Delete が呼ばれる
6. Repository.Delete が呼ばれる
7. DELETE文が実行される
8. 一覧画面へリダイレクトする

つまずき原因対応
登録ボタンを押してもActionに入らないformの asp-action が違うViewのformタグを確認する
入力値がModelに入らないasp-for やプロパティ名が違うModelとViewの対応を確認する
INSERTで主キーエラーになる既に存在する社員IDを指定している9000番台で未使用のIDを使う
INSERTで外部キーエラーになる存在しない部署IDを指定している部署IDは1〜5を使う
UPDATEしても変わらないemployee_id >= 9000 の条件に合っていない9000番台のデータだけ更新する
DELETEしても消えない9000番台以外を削除しようとしている研修用データだけ削除する
日付入力でエラーになる日付形式が合っていないtype="date" を使う
NULLを登録できないDBNull.Value を渡していない空欄の場合は DBNull.Value にする
更新後に再送信確認が出るPOST後にViewを直接返している成功時は RedirectToAction を使う

  • CRUDの意味を説明できる
  • GETとPOSTの使い分けを説明できる
  • 登録画面を表示できる
  • POSTされた入力値をModelで受け取れる
  • RepositoryでINSERTを実行できる
  • RepositoryでUPDATEを実行できる
  • RepositoryでDELETEを実行できる
  • ExecuteNonQuery の役割を説明できる
  • ModelState を使って入力エラーを表示できる
  • RedirectToAction で一覧画面へ戻れる
  • TempData で完了メッセージを表示できる
  • 更新・削除を9000番台に限定する理由を説明できる

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

制限時間は 100分 です。

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


課題20-1 EmployeeEditModelを作成する

Section titled “課題20-1 EmployeeEditModelを作成する”

登録・更新用の EmployeeEditModel を作成してください。

条件:

  • Models フォルダに作成する
  • EmployeeIdEmployeeNameYomiJobIdManagerIdHireDateSalaryCommissionDepartmentId を持つ
  • NULLになる可能性がある項目には ? を付ける

社員登録画面を作成してください。

条件:

  • Create Actionを作成する
  • Create.cshtml を作成する
  • EmployeeEditModel をViewに渡す
  • 社員ID、社員名、部署IDなどを入力できる

EmployeeRepositoryInsert メソッドを作成してください。

条件:

  • INSERT INTO employees を使う
  • SQLパラメーターを使う
  • ExecuteNonQuery を使う
  • NULLにする項目は DBNull.Value を渡す

課題20-4 登録後に一覧画面へ戻る

Section titled “課題20-4 登録後に一覧画面へ戻る”

登録処理が成功したら、一覧画面へ戻してください。

条件:

  • POST用 Create Actionを作成する
  • repository.Insert(model) を呼び出す
  • 成功時は RedirectToAction(nameof(Index)) を使う
  • TempData で登録完了メッセージを表示する

社員情報を更新できる画面を作成してください。

条件:

  • Edit(int id) Actionを作成する
  • FindEditById で既存データを取得する
  • Edit.cshtml を作成する
  • 既存値をフォームに表示する

EmployeeRepositoryUpdate メソッドを作成してください。

条件:

  • UPDATE employees を使う
  • SQLパラメーターを使う
  • employee_id >= 9000 の条件を入れる
  • 更新件数を戻り値として返す

課題20-7 削除確認画面を作成する

Section titled “課題20-7 削除確認画面を作成する”

削除前に確認画面を表示してください。

条件:

  • Delete(int id) Actionを作成する
  • Delete.cshtml を作成する
  • 社員ID、社員名、部署名を表示する
  • 9000番台以外は削除ボタンを表示しない

EmployeeRepositoryDelete メソッドを作成してください。

条件:

  • DELETE FROM employees を使う
  • SQLパラメーターを使う
  • employee_id >= 9000 の条件を入れる
  • 削除件数を戻り値として返す

課題20-9 一覧画面に操作リンクを追加する

Section titled “課題20-9 一覧画面に操作リンクを追加する”

一覧画面に、登録・更新・削除へのリンクを追加してください。

条件:

  • 「新規登録」ボタンを追加する
  • 9000番台のデータにだけ「更新」「削除」を表示する
  • 詳細リンクはこれまで通り表示する

課題20-10 入力チェックを追加する

Section titled “課題20-10 入力チェックを追加する”

登録・更新時に簡単な入力チェックを追加してください。

条件:

  • 社員IDは9000〜9999
  • 社員名は必須
  • 部署IDは1〜5
  • 給与と歩合は0以上
  • エラーがある場合は登録・更新しない

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

Terminal window
git status
git add .
git commit -m "Chapter20 MVC CRUD処理"
git push

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


  • EmployeeEditModel を作成している
  • 登録画面を作成している
  • 登録処理でINSERTを実行している
  • 更新画面を作成している
  • 更新処理でUPDATEを実行している
  • 削除確認画面を作成している
  • 削除処理でDELETEを実行している
  • SQLパラメーターを使っている
  • NULL項目に DBNull.Value を渡している
  • 9000番台だけ更新・削除できるようにしている
  • エラー時に画面へ戻れる
  • 成功時に一覧画面へ戻れる
  • Gitにcommitしている
  • Gitにpushしている

この章では、ASP.NET Core MVCアプリからOracle Databaseに対して、登録・更新・削除を行う基本的な流れを学習しました。

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

  • CRUDは、Create、Read、Update、Deleteの4つの基本操作である
  • 登録・更新・削除では、主にPOSTを使う
  • フォーム入力用のModelとして EmployeeEditModel を作成した
  • asp-for を使うと、Modelのプロパティと入力欄を対応させられる
  • INSERTUPDATEDELETE では ExecuteNonQuery を使う
  • SQLに値を渡すときはSQLパラメーターを使う
  • NULLとして登録・更新したい値には DBNull.Value を渡す
  • ModelState を使って入力エラーを表示できる
  • 処理成功後は RedirectToAction で一覧画面へ戻る
  • TempData を使うと、リダイレクト後にメッセージを表示できる
  • 研修では、既存データを守るために9000番台の社員IDだけ更新・削除対象にした

次章からは、デスクトップアプリ編 に入ります。

Windowsフォームアプリを作成し、ボタン、テキストボックス、DataGridViewなどを使いながら、デスクトップアプリの基本構成を体験します。