【T5b】モデルとデータベースの連携(後編)(7/8)
プロジェクトタイプ | (注意: 本文参照) |
---|
プロジェクト名 | T5b |
---|
ソリューション名 | PIT5 |
---|
注意
- 本ページの作業内容は 前のページまでの続き になっていることに注意せよ.
- 先に前のページまでをすべて読み,指示されている作業を済ませてから本ページを読むこと.
- プロジェクトの作成作業については準備作業を参照せよ.
5b-7. Editアクションとビューの作成
次に,個々の学生の詳細情報を編集するためのアクションEdit
を作成しよう.
StudentsController
クラスに_に示すメソッドを追加する.
StudentsControllerクラスの変更内容(Editアクション(GET用)) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // Editアクション(GET用)
public IActionResult Edit(int? id)
{
if (id == null) // idが指定されなかったら
return NotFound(); // 404 Not Found
var student = (from s in _context.Students //
where s.Id == id // LINQを用いてidで指定された学生情報を探す
select s).FirstOrDefault(); //
if (student == null) // idで指定された学生が
return NotFound(); // 見つからなかったら 404 Not Found
return View(student); // 見つかった学生情報をビューに渡す
}
|
このEdit()
メソッドはメソッド名を除けばリスト5b-6-1のDetails()
メソッドと全く同じである.
次にこのアクション用のビューを作成する. Views/Students フォルダにEdit
という名前のビューを追加する.
Views/Students/Edit.cshtml を_のように変更する.
Views/Students/Edit.cshtmlの変更内容 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
| @model Student
@{
ViewData["Title"] = "学生情報の編集";
if (Model is null) throw new ArgumentNullException(nameof(Model)); // ad-hoc! 非null保証のための回避策
}
<form asp-action="Edit">
@* IDの表示(これは編集させない) *@
<label asp-for="@Model.Id"></label>:
<input type="hidden" asp-for="@Model.Id" />
@Html.DisplayFor(s => s.Id)
<br />
@* 姓(LastName) のための入力欄 *@
<label asp-for="@Model.LastName"></label>:
<input asp-for="@Model.LastName" />
<span asp-validation-for="@Model.LastName"></span>
<br />
@* 名(FirstName) のための入力欄 *@
<label asp-for="@Model.FirstName"></label>:
<input asp-for="@Model.FirstName" />
<span asp-validation-for="@Model.FirstName"></span>
<br />
@* 性別(Sex) のための入力欄 *@
<label asp-for="@Model.Sex"></label>:
<select asp-for="@Model.Sex" asp-items="Html.GetEnumSelectList<SexType>()"></select>
<span asp-validation-for="@Model.Sex"></span>
<br />
@* 電話番号(PhoneNumber) のための入力欄 *@
<label asp-for="@Model.PhoneNumber"></label>:
<input asp-for="@Model.PhoneNumber" />
<span asp-validation-for="@Model.PhoneNumber"></span>
<br />
@* メールアドレス(Mail) のための入力欄 *@
<label asp-for="@Model.Mail"></label>:
<input asp-for="@Model.Mail" />
<span asp-validation-for="@Model.Mail"></span>
<br />
@* 誕生日(Birthday) のための入力欄 *@
<label asp-for="@Model.Birthday"></label>:
<input asp-for="@Model.Birthday" />
<span asp-validation-for="@Model.Birthday"></span>
<br />
@* 登録日時(Registered)の表示(これは編集させない) *@
<label asp-for="@Model.Registered"></label>:
<input type="hidden" asp-for="@Model.Registered" />
@Html.DisplayFor(s => s.Registered)
<br />
<input type="submit" value="送信" />
</form>
<a asp-action="Details" asp-route-id="@Model.Id">詳細に戻る</a>
@section Scripts
{
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
|
これもリスト5b-5-2の Create.cshtml とほとんど違いがない.
注目するべきは,すべての項目が編集可能になってはいないことである._の強調した二か所では,
Id
プロパティとRegister
プロパティに関しては単に値を表示するだけで入力欄を設けていない.
ここで重要な点は,いかなるウェブアプリケーションであっても既存のレコードを編集する際は 主キーは決して変更させない ということである.
使用しているデータベース製品にもよるが,新規レコードのための主キーはデータベースサーバ側で管理されているため,
既存レコードの主キーを自由に変更できるようにしてしまうとテーブル内のレコードとの整合性が保てなくなってしまう.
このため_の10~14行目では主キーは表示するだけで入力欄を用意していない.
52~56行目で登録日時も同様に表示するだけで入力欄を用意していないが,「登録日時」は
その名の通りその学生を最初に登録した日時を記録するためのレコードであるためである.
ただしこれらのデータは入力欄を作ってはいないが, type 属性に"hidden"
を指定した
input 要素でサーバ側に送られるようになっている .変更しないデータが無意味にアクションメソッドと
ビューの間を往復することになるが,変更するデータだけをビューから送信させてそれのみを既存データに反映させるのは
それほど難しいことではない.
次にこのフォームの送信に対応するアクションメソッドを用意しよう.
StudentsController
クラスに_に示すメソッドを追加する.
StudentsControllerクラスの変更内容(Editアクション(POST用)) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| // Editアクション(POST用)
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(int id, Student student)
{
if (id != student.Id) // ルーティングパラメータと
return NotFound(); // 送信されたデータが食い違っていた場合は
// 404 Not Found
if (ModelState.IsValid) // 入力値に誤りがない場合のみデータベースへの登録処理を行う.
{
_context.Update(student); // 学生情報を更新する.
_context.SaveChanges(); // データベースに変更を保存する.
return RedirectToAction(nameof(Details), new { id = student.Id }); // Details に遷移する.
}
else
{
return View(student); // エラーがあった場合は元のビューに戻る
}
}
|
これも,Update()
メソッドを使っている点を除けばリスト5b-5-3のCreate()
メソッドとほとんど同じである.
15行目ではRedirectToAction()
メソッドを使ってDetails
アクションに転送している.
メソッドの第二引数に指定している"new { id = student.Id }"
はルーティングパラメーターを指定するものである.
"new { ... }"
という見慣れない記述が登場しているが,これは匿名クラスという
匿名の型のオブジェクトをインラインで生成するための記法である.ここではこのアプリで使用しているルーティングパラメーターと
同名のプロパティを定義することでid
パラメーターを指定している.
同じ方法を用いてCreate
アクションからDetails
アクションへの遷移も実装しておこう.
リスト5b-5-3の時点ではDetails
アクションを実装していなかったので,代わりにIndex
アクションに遷移するようにしていたが,
Controllers/StudentsController.cs のCreate()
メソッド(POST用)を_に示すように変更しよう.
StudentsControllerクラスの変更内容 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| // Createアクション(POST用)
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create([Bind("FirstName, LastName, Sex, PhoneNumber, Mail, Birthday")]Student student)
{
if (ModelState.IsValid)
{
student.Registered = DateTime.Now;
_context.Add(student);
_context.SaveChanges();
return RedirectToAction(nameof(Details), new { id = student.Id }); // Details に遷移する.
}
else
{
return View(student);
}
}
|
ここまで書けたら実行してみよう.一覧に表示されている学生のリンクをクリック→「編集」のリンクをクリックして
Edit
アクションにアクセスし,学生の詳細情報を適当に編集して「送信」ボタンをクリックしてみよう(_~_).
Details
アクションに遷移して,編集内容が反映されたことが分かるはずである(_).
実行結果Last updated on 2024-05-10
Published on 2024-05-10