情報応用演習Ⅰ(2024)

【T5b】モデルとデータベースの連携(後編)(6/8)

プロジェクトタイプ(注意: 本文参照)
プロジェクト名T5b
ソリューション名PIT5
注意
  • 本ページの作業内容は 前のページまでの続き になっていることに注意せよ.
    • 先に前のページまでをすべて読み,指示されている作業を済ませてから本ページを読むこと.
    • プロジェクトの作成作業については準備作業を参照せよ.

5b-6. Detailsアクションとビューの作成

次に,個々の学生の詳細情報を表示するためのアクションDetailsを作成しよう. StudentsControllerクラスに_に示すメソッドを追加する.

StudentsControllerクラスの変更内容(Detailsアクション(GETのみ))
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// Detailsアクション(GETのみ)
public IActionResult Details(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);                         // 見つかった学生情報をビューに渡す
}

Details()メソッドにidという引数が定義されている.これは ルーティングパラメータ と呼ばれるものである. これは Program.cs におけるURLルーティングの定義に現れている. Program.cs のapp.UseEndpoint()メソッドの呼び出しを見てみよう. 現状では_のようになっているはずである.

Program.csのURLルーティングの定義
 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
using KnzwTech.AspNetCore.ResourceBasedLocalization;
using Microsoft.EntityFrameworkCore;
using T5b.Data;

AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews(opt => opt.EnableDefaultErrorMessagesFromResource());

builder.Services.AddDbContext<T5bContext>(opt
    => opt.UseNpgsql(builder.Configuration.GetConnectionString(nameof(T5bContext))));

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();

app.UseStatusCodePagesWithReExecute("/Home/AccessError/{0}");

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

第01回で説明したように,"{controller=Home}/{action=Index}/{id?}"の部分が URLとコントローラーのメソッドのマッピングを指定している部分である.この文字列の最後の{id?}の部分が このアプリで定義しているルーティングパラメーターである.Detailsアクションでは, 表示するべき学生のIDを指定するのにルーティングパラメーターを使用している.これにより http://localhost:ポート番号/Students/Details/学生のIDというURLにアクセスすることにより, 学生のIDで指定したIDをもつ学生を表示するようにしている. マッピング定義の文字列の{id?}には?がついているがこれはこのパラメーターが「省略可能」であることを示している. このURLルーティングの定義の詳細については Routing to controller actions in ASP.NET Core - Microsoft Docs を参考にするとよい.

_Details()メソッドの引数も省略可能であることを考慮して, int のNull許容型となっている. なお, このアクションメソッドの引数名とapp.MapControllerRoute()メソッドで指定したルーティングパラメーター名は 正確に一致させる必要がある .今回はapp.MapControllerRoute()メソッドで"{controller=Home}/{action=Index}/{id?}"と 指定しているため,ルーティングパラメーターの名前はidであり,このため_Details()メソッドの 引数名もidにして一致させている.

_の4~5行目ではこの引数が null つまりは指定されていない場合はNotFound()メソッドを呼び出している. これはクライアントに404 Not Found,つまり「要求されたリソースが見つからない」ということをクライアントに通知するためのHTTPレスポンスを返すメソッドである.

また,_の7~9行目ではLINQを用いてid引数に渡された値と同じIDを持つ学生情報を探している. 見つからなかった場合(11~12行目)にもNotFound()メソッドを呼び出している. 見つかった場合は,見つかった学生情報─つまりStudentクラスのインスタンスをビューに渡している.

そのアクションメソッドが,ルーティングパラメーターなどの入力に対してどのようなレスポンスを返すべきかは,アプリケーション次第 なので HTTPをよく理解したうえで慎重に選択する必要がある.

このDetailsアクションに対応するビューを作成しよう. Views/Students フォルダにDetailsという名前のビューを追加する. Views/Students/Details.cshtml を_のように変更する.

Views/Students/Details.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
@model Student

@{
    ViewData["Title"] = "学生詳細";

    if (Model is null) throw new ArgumentNullException(nameof(Model)); // ad-hoc! 非null保証のための回避策
}

<table>
  <tr><th>項目</th><th></th></tr>

  @* IDの表示 *@
  <tr>
     <td>@Html.DisplayNameFor(s => s.Id)</td>
     <td>@Html.DisplayFor(s => s.Id)</td>
  </tr>

  @* 姓(LastName)の表示 *@
  <tr>
     <td>@Html.DisplayNameFor(s => s.LastName)</td>
     <td>@Html.DisplayFor(s => s.LastName)</td>
  </tr>

  @* 名(FirstName)の表示 *@
  <tr>
     <td>@Html.DisplayNameFor(s => s.FirstName)</td>
     <td>@Html.DisplayFor(s => s.FirstName)</td>
  </tr>

  @* 性別(Sex)の表示 *@
  <tr>
     <td>@Html.DisplayNameFor(s => s.Sex)</td>
     <td>@Html.DisplayFor(s => s.Sex)</td>
  </tr>

  @* 電話番号(PhoneNumber)の表示 *@
  <tr>
     <td>@Html.DisplayNameFor(s => s.PhoneNumber)</td>
     <td>@Html.DisplayFor(s => s.PhoneNumber)</td>
  </tr>

  @* メールアドレス(Mail)の表示 *@
  <tr>
     <td>@Html.DisplayNameFor(s => s.Mail)</td>
     <td>@Html.DisplayFor(s => s.Mail)</td>
  </tr>

  @* 誕生日(Birthday)の表示 *@
  <tr>
     <td>@Html.DisplayNameFor(s => s.Birthday)</td>
     <td>@Html.DisplayFor(s => s.Birthday)</td>
  </tr>  
  
  @* 登録日時(Registered)の表示 *@
  <tr>
     <td>@Html.DisplayNameFor(s => s.Registered)</td>
     <td>@Html.DisplayFor(s => s.Registered)</td>
  </tr>
</table>

<a asp-action="Index">一覧に戻る</a>
| <a asp-action="Edit" asp-route-id="@Model.Id">編集</a>
| <a asp-action="Delete" asp-route-id="@Model.Id">削除</a>

Html.DisplayNameFor()Html.DisplayFor()HTMLヘルパー と呼ばれるもので, HTML生成を補助するための機能である.Html.DisplayNameFor()は指定したモデルクラスのプロパティの表示名を取得するためのものであり, Html.DisplayFor()は指定したモデルクラスのプロパティの値を取得するためのものである. 後者に関しては,単に値を表示するだけなのでたとえばFistNameプロパティであれば, @Html.DisplayFor(s => s.FirstName) と書く代わりに単に @s.FirstName と書いても同じではある. ただし,列挙型を使用しているSexプロパティのように 設定値がそのまま表示名ではない 場合もあるので, そのような場合はHtml.DisplayFor()を用いることで「値の表示名」を得ることができる1

62,63行目ではそれぞれEditDeleteアクションへのリンクを貼っている. ルーティングパラメーターを指定する場合は asp-route-タグヘルパー を用いる. asp-route-ルーティングパラメーター名=のように指定することで指定した ルーティングパラメーターをもつリンクを生成することができる.

Indexアクションの一覧の各学生にも同じ方法でDetailsアクションのリンクを貼っておこう. Views/Students/Index.cshtml を_に示すように変更する.

Views/Students/Index.cshtmlの変更内容
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@model IEnumerable<Student>

@{
    ViewData["Title"] = "学生一覧";
    
    if (Model is null) throw new ArgumentNullException(nameof(Model)); // ad-hoc! 非null保証のための回避策
}

<p>人数:@Model.Count()</p>

<ul>
    @foreach(var s in Model)
    {        
        <li><a asp-action="Details" asp-route-id="@s.Id">@s.Id: @s.LastName @s.FirstName</a></li>
    }
</ul>

<a asp-action="Create">新規作成</a>

ここまで書けたら実行してみよう.一覧に表示されている学生のリンクをクリックしてDetailsアクションにアクセスすると その学生の詳細情報が表示されることを確認しよう(__).

実行結果

ここで「メールアドレス」の項目に着目しよう._ではこの項目に対して リンク( a 要素)を張っていないがモデルクラスの対応するプロパティ(Mailプロパティ)に [EmailAddress]属性を指定しているため,メールアドレスの部分に自動的にmailto:リンクが 付与されていることが分かるだろう.

また「誕生日」や「登録日時」もそれぞれ日付部分のみ,日付と時刻込みで表示されている.これらも モデルクラスの対応するプロパティ(BirthdayプロパティおよびRegisteredプロパティ)に [DataType]属性を指定した効果である.


  1. HTMLヘルパーと以前に説明したタグヘルパーは機能的に競合する部分がある.HTMLヘルパーは.NET FrameworkのASP.NETの時代からある記法で将来的にはタグヘルパーに置き換えられるかもしれない.これらのHTMLヘルパーをタグヘルパーで置き換えるTagHelperPackというライブラリもある. ↩︎

Last updated on 2024-05-10
Published on 2024-05-10

Powered by Hugo. Theme by TechDoc. Designed by Thingsym.