情報応用演習Ⅰ(2024)

【T8a】多対多のリレーションシップ(3/8)

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

8a-3. コレクションナビゲーションプロパティ

前章では,「学生」を表すモデルクラスStudent_に示すような 参照ナビゲーションプロパティ を追加していた.

Studentクラスの内容(再掲)
 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
// 「学生」クラス
public class Student
{
    [Display(Name = "ID")]
    public int Id { get; set; }                   // ID

    [Display(Name = "姓")]
    public string LastName { get; set; } = "";    // 姓

    [Display(Name = "ミドルネーム")]
    public string? MiddleName { get; set; }       // ミドルネーム

    [Display(Name = "名")]
    public string FirstName { get; set; } = "";   // 名

    [Display(Name = "性別")]
    public SexType Sex { get; set; }              // 性別

    [Phone]
    [Display(Name = "電話番号")]
    public string PhoneNumber { get; set; } = ""; // 電話番号

    [EmailAddress]
    [Display(Name = "メールアドレス")]
    public string? Mail { get; set; }             // メールアドレス

    [DataType(DataType.Date)]
    [Display(Name = "誕生日")]
    public DateTime? Birthday { get; set; }       // 誕生日

    [DataType(DataType.DateTime)]
    [Display(Name = "登録日時")]
    public DateTime Registered { get; set; }      // 登録日時

    [Display(Name = "所属学科")]
    public int DepartmentId { get; set; }         // ① 外部キー(Departmentを参照)

    public Department? Department { get; set; }   // ② ↑のためのナビゲーションプロパティ
}

参照ナビゲーションプロパティは一対多のリレーションシップのうち,「多」の側から「一」の側をプログラム上で 参照するためのものである.この場合で言えばDepartmentプロパティは,その学生が所属している 学科の情報を「手繰り寄せる」プロパティである.

EF Core では逆に,「一」の側から「多」の側を参照するためのナビゲーションプロパティである コレクションナビゲーションプロパティ も定義することが可能である. 今回の場合であれば, 「学科」からその学科に所属する「学生」のコレクションを参照するものである. _はこれらの二種類のナビゲーションプロパティの関係を示している. 実際にコレクションナビゲーションプロパティを定義してみよう. Models/Department.cs に_に示す内容を追記しよう.

Departmentクラスの追記内容
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 「学科」クラス
public class Department
{
    [Display(Name = "ID")]
    public int Id { get; set; }

    [Display(Name = "学科名")]
    public string Name { get; set; } = "";

    public List<Student>? Students { get; set; } // この「学科」に所属する全「学生」を参照するための
                                                 // コレクションナビゲーションプロパティ
}

コレクションナビゲーションプロパティを利用するには,「一」の側のモデルクラスにList<「多」側のモデルクラス>の Null許容型のプロパティを定義する.プロパティ名に関する制限はないがよく「『多』側のモデルクラスの複数形」の名前が用いられる. 第07回では「多」側のモデルクラスで参照ナビゲーションプロパティだけを定義したが, 通常は「一」側のモデルクラスのコレクションナビゲーションとセットで定義することが多い

このDepartmentクラスの内容を表示するためのコントローラーを作成し,コレクションナビゲーションプロパティを経由して 各学科に所属する学生の一覧を作成してみよう.今回は学科の一覧と学科の詳細情報を表示するだけのコントローラー Departments(クラス名としてはDepartmentsController)を作成する.簡略化のため「学科」の情報の新規作成や更新の機能はここでは作成しない. このコントローラーは_に示す通りIndexアクションとDetailsアクションのみをもつ.

Departmentsコントローラー周りの画面イメージと画面遷移

それではプロジェクト内の Controllers フォルダを右クリックし「追加」→「コントローラー」をクリックしよう. 「MVC コントローラー - 空」を選択して「追加」ボタンをクリックし,「名前」にDepartmentsControllerと指定する( .cs は省略可能). DepartmentsController.cs が追加されるので_に示す内容を追記しよう.

DepartmentsControllerクラスの変更内容
 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
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; // 追記
using T8a.Data;                      // 追記
using T8a.Models;                    // 追記

namespace T8a.Controllers
{
    public class DepartmentsController : Controller
    {
        private readonly T8aContext _context;

        public DepartmentsController(T8aContext context) 
        {
            _context = context;
        }

        // Indexアクション(GETのみ)
        public IActionResult Index()
        {
            var dpts = (from d in _context.Departments
                        orderby d.Id ascending
                        select d);

            return View(dpts.ToList());
        }

        // Detailsアクション(GETのみ)
        public IActionResult Details(int? id) 
        {
            if (id == null)
                return NotFound();

            var dpt = (from d in _context.Departments
                       where d.Id == id
                       select d)
                       .Include(d => d.Students)
                       .FirstOrDefault();

            if (dpt == null)
                return NotFound();

            return View(dpt);
        }
    }
}

ここでは技術的に新しい要素は特段ない.学科詳細画面(Details)ではその学科に所属する学生の一覧を表示するので 先ほど定義したコレクションナビゲーションプロパティStudentsを使用する必要がある.そのため36行目で.Include()メソッドを 呼び出している.つぎにこれらのアクションのためのビューを追加しよう.

まずIndexアクションのためのビューを作成しよう.手動で .cshtml ファイルを作成して適切な場所に配置するか, あるいはVisual Studio の機能を使ってRazorビューを作成しよう. Views/Departments/Index.cshtml を_のように記述する.

Views/Departments/Index.cshtmlの変更内容
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@model IEnumerable<Department>

@{
    ViewData["Title"] = "学科一覧";

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

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

ここでは学科の一覧を番号なしリスト( ul 要素)で表示している. 各学科名にはその詳細画面,つまりDetailsアクションへのリンクを貼っている. つぎはそのDetailsアクションのためのビューを作成しよう. Views/Departments/Details.cshtml を_のように記述する.

Views/Departments/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
@model Department

@{
    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(d => d.Id)</td>
    <td>@Html.DisplayFor(d => d.Id)</td>
  </tr>

  @* 学科名(Name)の表示 *@
  <tr>
    <td>@Html.DisplayNameFor(d => d.Name)</td>
    <td>@Html.DisplayFor(d => d.Name)</td>
  </tr>

  @* コレクションナビゲーションプロパティを用いた所属学生の表示 *@
  <tr>
    <td>所属学生</td>
    <td>
      <ul>
        @foreach(var s in Model.Students!)
        {
            <li>
              <a asp-controller="Students" asp-action="Details" asp-route-id="@s.Id">
                @s.LastName @s.FirstName
              </a>
            </li>
        }
      </ul>
    </td>
  </tr>

</table>

ここでは表( table 要素)で各学科のID,学科名,そして所属学生を表示している. 28~37行目では表のセル内に番号なしリスト( ul 要素)を置いて,先ほど定義したコレクションナビゲーションプロパティである Studentsプロパティを使用して所属している学生の一覧を作成している. 各学生の姓名にはStudentsコントローラーのDetailsアクションへのリンクを貼っている.

いまのところプログラム起動時にはHomeコントローラーのIndexアクションが表示されるようになっているが, このページにDepartmentsコントローラーのIndexアクションへのリンクを作っておこう. Views/Home/Index.cshtml を_に示すように変更する.

Views/Home/Index.cshtmlの変更内容
1
2
3
4
5
6
7
8
@{
    ViewData["Title"] = "Home Page";
}

<ul>
    <li><a asp-controller="Students" asp-action="Index">学生管理</a></li>
    <li><a asp-controller="Departments" asp-action="Index">学科管理</a></li>
</ul> 

ここまで書けたら実行してみよう.「学科管理」のリンクをクリックしてDepartmentsコントローラーの Indexアクションにアクセスしてみよう(_)._に示す通り学科の一覧がリストとして表示されるはずである. また,いずれかの学科のリンクをクリックしてDetailsアクションにアクセスしてみよう. _に示す通り,学科のID,学科名,そして所属学生の一覧が表示されるはずである. また,各学生のリンクをクリックすると_に示すようにStudentsコントローラーのDetailsアクションに 遷移するはずである.

実行結果
Last updated on 2024-06-10
Published on 2024-06-10

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