【ASP.NET】Web未経験者がASPのMSDNチュートリアルやってみる（モデルの追加）

タイトル通り、Web未経験のエンジニアがASP.NETでMSDNのチュートリアルに沿って慣れてみようという内容です。
筆者のステータスはこんな感じ。

- VB.NET経験あり
- C#独学
- Web未経験（何それおいしいの？）

時代はWebだということで、手を出してみます。
手を出すチュートリアルはコチラ。

https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/razor-pages/?view=aspnetcore-2.1&preserve-view=true

今回はMSDNのチュートリアル「ASP.NET Core で Razor ページ アプリにモデルを追加する」を進めます。

https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/razor-pages/model?view=aspnetcore-2.1&tabs=visual-studio

尚、前回実施したチュートリアルの導入編の続きから始めます。

https://qiita.com/green_fox/items/ddedd862145ce7c5fdf7

#作成の流れ
まずは今回の作成の流れを確認します。MSDNのチュートリアルに沿って次の様に進めます。

1. データモデルの追加
2. モデルのスキャフォールディング
3. 初期移行
4. 実行

今回のチュートリアルも簡単そうに見えますね。

##1. データモデルの追加
まずはデータモデルの追加を実施します。
しかし、初めてASP.NETを触る人にとっては、「データモデルって何？」ってなります。私もなりました。
MSDNのチュートリアルでは、

> アプリのモデル クラスでは、Entity Framework Core (EF Core) を使用して、データベースを操作します。

とあります。いまいちピンときません。ちょっと調べてみました。

### 寄り道①モデルって何？
気になったので調べてみましたが、MSDN特有の言い回しに辟易してしまったので、MSDN以外のサイトも調べてみました。
その中で、[【ASP.NET MVC入門その2】ASP.NET MVCでModelクラスの実装](https://www.fenet.jp/dotnet/column/tool/641/#:~:text=ASP.NET%20MVC%E3%81%AEModel%E3%81%A8%E3%81%AF%E3%80%81%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E3%82%84%E3%82%8A%E3%81%A8%E3%82%8A,%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E6%A4%9C%E7%B4%A2%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)のページにモデルの説明があり、そこには、

> ASP.NET MVCのModelとは、データのやりとりをするためのクラスです。

と説明してくれています。
なるほど、データベースを操作するためのクラスということですね。
VB.NETで言うところの「OleDbConnection クラス」みたいなものでしょうか。
※間違ってたらすみません。

### 寄り道②MVCって何？
モデルを調べていて気になったのがもう一つ。MVCという単語です。「ASP.NET モデル」で検索すると、「MVC」という単語が必ずセットでついてきます。
MVCを調べて見ると、MVCについてマイクロソフトが説明しています。

https://dotnet.microsoft.com/ja-jp/apps/aspnet/mvc#:~:text=MVC%20%E3%81%AF%E3%80%81%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%20%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%95%E3%82%A7%E3%82%A4%E3%82%B9%20(%E3%83%93%E3%83%A5%E3%83%BC,%E3%81%95%E3%82%8C%E3%82%8B%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%20%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E3%81%A7%E3%81%99%E3%80%82&text=%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9%E3%83%BC%E3%81%AF%E3%80%81%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E3%83%93%E3%83%A5%E3%83%BC,%E3%83%9A%E3%83%BC%E3%82%B8%E3%82%92%E3%83%AC%E3%83%B3%E3%83%80%E3%83%AA%E3%83%B3%E3%82%B0%E3%81%97%E3%81%BE%E3%81%99%E3%80%82

どうやら、MVCというのは、**Model-View-Controller**の略で、アーキテクチャのデザインパターンの一つであり、UI作成のために使われるようです。

- Model…データ
- View…ユーザー インターフェイス
- Controller…アプリケーション ロジック

なるほど。
忘れてしまいそうですが、これはチュートリアルです。
チュートリアルで言ってる「データモデルの追加」というのは、「データをやり取りするためのコーディングをしましょう」ということですね。

### 気を取り直してデータモデルの追加
というわけでチュートリアルの「データモデルの追加」に戻ります。
MSDNの記載から流れを確認すると、

1-1. 「Models」フォルダを追加
1-2. 「Movie」クラスを追加
1-3. 「Movie」クラスにプロパティを作成

となっています。

####1-1.「Models」フォルダを追加

まずは、Visual Studio で前回のチュートリアルで作成したプロジェクト「RazorPagesMovie」を開きます。

RazorPagesMovie プロジェクトを右クリックして、コンテキストメニューから「追加」→「新しいフォルダー」を選択し、プロジェクト内にフォルダを追加します。

![20220222_001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/053f7838-4240-02fd-a365-96bca9a7bc70.png)

すると、「新しいフォルダー」がソリューションエクスプローラー上に作成されます。
![20220222_002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/763d258c-ddee-a96b-e94d-4ea846331b91.png)

このフォルダの名前を、「Models」に変更します。
![20220222_003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/2d9d5bf2-86e6-cf80-c1ea-d46ded1b9579.png)


####1-2.「Movie」クラスを追加
「Models」フォルダを追加したら、「Movie」クラスを追加します。
「Models」フォルダを右クリックしてコンテキストメニューを開き、「追加」→「クラス」を選択します。

![20220222_004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/9cc73327-d728-79a8-d394-e0cda155e8bb.png)

「新しい項目の追加」画面がポップアップされるので、「クラス」を選んで、名前を「Movie」にして、追加をクリックします。
![20220222_005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/b75dc74c-f8be-ccf6-d3fc-b75d997b4a06.png)
すると、ソリューションエクスプローラーの「Models」フォルダの中に「Movie.cs」が作成されます。
![20220222_006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/b4ebbfd5-3693-c6df-f1de-81e7c3fb59fb.png)

####1-3.「Movie」クラスにプロパティを作成
「Movie」クラスを作成したら、今度は「Movie」クラスにプロパティを作成します。
ひとまず、MSDNのソースコードをそのままコピペ。

```c#
using System;
using System.ComponentModel.DataAnnotations;

namespace RazorPagesMovie.Models
{
    public class Movie
    {
        public int ID { get; set; }
        public string Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }
}
```
プロパティは、

- ID…ID
- Titel…タイトル
- ReleaseDate…発売日
- Genre…ジャンル
- Price…価格

と言うところでしょうか。気になるのはこの1行。

```c#
[DataType(DataType.Date)]
```
これはプロパティに対して型を指定しているのですが、対象となるプロパティは、

```c#
public DateTime ReleaseDate { get; set; }
```
だけです。1行にまとめてもエラーが出ないので、こんな感じに書くと分かりやすいですね。

```c#
[DataType(DataType.Date)]public DateTime ReleaseDate { get; set; }
```

##2.モデルのスキャフォールディング
データモデルのプロパティを作成したら、モデルのスキャフォールディングを行います。
…スキャフォールディングという、見たことも聞いたこともない単語が登場しました。

###スキャフォールディングって何？
というわけで調べてみましょうスキャフォールディング。
CodeZineで分かりやすくまとめられています。

https://codezine.jp/article/detail/7491

>Scaffolding（スキャフォールディング）とは、データモデルとなる型を元に、いわゆるCRUD（Create/Read/Upadate/Delete)と呼ばれる追加、読込、変更、削除を行う画面とそのコードを自動で生成する機能のことです。
Scaffoldingを和訳すると「足場」という言葉であり、その名のとおり少ない手間でアプリケーションの「足場」となる大枠の構造を作ることを目的としています。従って、Scaffoldingは完全なアプリケーションを作るための機能ではない、ということは認識しておく必要があります。

なるほど。
作成したモデルを元にして、データ操作に必要な機能を自動で作ってくれるみたいですね。
ただし、大枠の構造を作るだけで、他の機能については自分で実装する必要があるようです。

###スキャフォールディングしてみる
ではスキャフォールディングを実行してみます。
まず、ソリューションエクスプローラーの「Pages」フォルダを右クリックしてコンテキストメニューを開き、「追加」→「新しいフォルダー」を選択して、「Movies」フォルダを作成します。
![20220222_007.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/f5042cac-98f0-aa66-b83b-9a54217827d8.png)
こんな感じに「Pages」「Movies」フォルダを作ります。
![20220222_008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/e630bdec-9b76-e472-aad2-0518267bf1d6.png)
「Pages」フォルダの中に「Movies」フォルダを作成したら、「Movies」フォルダを右クリックしてコンテキストメニューを開き、「追加」→「新規スキャフォールディングアイテム」をクリックします。
![20220222_009.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/9afcd9e5-5cff-4f42-2ede-17240eaaa9ae.png)
すると、「新規スキャフォールディング アイテムの追加」のポップアップが出て来るので、**「Entity Framework を使用する Razor ページ (CRUD)」**を選択して追加ボタンをクリック。
![20220222_010.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/d6ecdf54-9c48-4885-69bb-2469d3fa6ddb.png)
またまた少し寄り道を。
**CRUD**というまたまた新しい単語が出てきていますが、これは、

- **C**reate（作成）
- **R**ead（参照）
- **U**pdate（更新）
- **D**elete（削除）

の頭文字を取ったもので、データベース操作の基本的な機能です。DBMSにおけるDML（データ操作言語）に相当するものです。

話を戻して、「新規スキャフォールディング アイテムの追加」画面で、**「Entity Framework を使用する Razor ページ (CRUD)」**を選択して追加ボタンをクリックしたところです。
すると、「Entity Framework を使用する Razor ページ (CRUD)の追加」というポップアップが出てきます。
![20220222_011.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/a1e89f29-5167-2c8b-ee26-ee5619e6ad51.png)
初期状態だと上図の様に空っぽなので、**「モデル クラス」**と**「データ コンテキスト クラス」**を設定します。
**「モデル クラス」**は、リストから**Movie (RazorPagesMovie.Models)**を選択します。![20220222_012.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/04f9559c-ecb9-30d0-1020-f187dfa17dde.png)
**「データ コンテキスト クラス」**は、右にある「+」ボタンをクリックすると「データコンテキストの追加」のポップアップ画面が出て来るので、「新しいデータコンテキスト型」に「RazorPagesMovie.Data.RazorPagesMovieContext」を設定します。
![20220222_013.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/13ef8889-55c0-43c4-a73b-bee963f5dbcb.png)
MSDNのチュートリアルでは、

>RazorPagesMovie.**Models**.RazorPagesMovieContext を RazorPagesMovie.**Data**.RazorPagesMovieContext に変更します。

とありますが、チュートリアル通りに進めると、「RazorPagesMovie.Data.RazorPagesMovieContext」がデフォルトで入っているはずです（私はそうでした）。
下の画像の様に設定したら追加ボタンをクリックします（チェックボックスは何も触らない）。
![20220222_014.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/b9292e80-8c73-e9f7-d90e-455e25d13bb3.png)
すると、「スキャフォールディングしています…」という画面が出て来るので、しばらく待ちます。
![20220222_015.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/c34c476e-17ac-7192-72e4-daba3e0b17dd.png)

スキャフォールディングが完了すると、ファイルとフォルダが作成されます。
まず、「Movies」フォルダ内には次のcshtmlファイルが作成されています。

- Create.cshtml
- Delete.cshtml
- Details.cshtml
- Edit.cshtml
- Index.cshtml

ソリューションエクスプローラーで見るとファイルが作成されていることが分かります。
![20220222_016.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/17f2a2d4-5490-080d-6c27-e6d573fa42db.png)
また、RazorPagesMovieプロジェクトの直下に「Data」フォルダが作成され、その中に **RazorPagesMovieContext.cs** ファイルが作成されます。
![20220222_017.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/8c65926c-0027-e7f4-7bff-df4269d8acd9.png)
これでスキャフォールディングは完了し、DB操作に必要がhtmlファイルが生成されました。

##3. 初期移行
スキャフォールディングが完了したら、「パッケージ マネージャー コンソール」から初期移行を実施します。
といっても、MSDNのチュートリアルではコンソール画面にコマンドを入力して実行しているだけなので簡単です。
###コマンドの実行
Visual Studio のメニュー画面の「ツール」を開き、「NuGetパッケージマネージャー」→「パッケージ マネージャー コンソール」を選択します。
![20220222_018.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/28b3e7f3-2d13-d790-5ad1-cfabd78dd36c.png)
すると、Visual Studio の画面の下に「パッケージ マネージャー コンソール」が出現します。
![20220222_019.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/d03d503f-2232-ccd8-da25-75fcda9df1c7.png)
上の画像の赤枠で囲った部分が「パッケージ マネージャー コンソール」です。
ここに、コマンドを入力します。
まずは、
　**Add-Migration InitialCreate**
と入力して、Enterキーを押下。
![20220222_020.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/b0e5a471-c5e8-4330-fb85-3c01587e3c09.png)
「Build succeeded.」と出ていれば完了です。
![20220222_021.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/86c28221-7554-c72b-e356-b1c4ee27fd95.png)
次に、
　**Update-Database**
と入力して、Enterキーを押下。
![20220222_022.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/806d92bb-6c47-23f4-05f9-0dcbf2b58219.png)
こちらも「Build succeeded.」と出ていれば完了です。
![20220222_023.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/cb1a695b-2ffb-51ce-f79a-ff4b34b6cd4b.png)
そして上記のコマンドを実行すると、ソリューションエクスプローラーに「Migrations」フォルダが作成されます。
![20220222_024.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/b2b06f45-9a19-1809-4d3b-ee0c64b2b469.png)
…何か気が付いたら作成されていたので、MSDNのチュートリアルに書かれていることを忖度しながら解読してみます。
まず、**Add-Migration InitialCreate** コマンドの実行で、「Migrations」フォルダが作成され、その中に「yyyymmddhhmiss_InitialCreate.cs」と「RazorPagesMovieContextModelSnapshot.cs」の2ファイルが作成されます。
その次の、**Update-Database** コマンドの実行で、「yyyymmddhhmiss_InitialCreate.cs」のUpメソッドが実行されます。

```c#
protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.CreateTable(
        name: "Movie",
        columns: table => new
        {
            ID = table.Column<int>(nullable: false)
                .Annotation("SqlServer:Identity", "1, 1"),
            Title = table.Column<string>(nullable: true),
            ReleaseDate = table.Column<DateTime>(nullable: false),
            Genre = table.Column<string>(nullable: true),
            Price = table.Column<decimal>(nullable: false)
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_Movie", x => x.ID);
        });
}
```
なるほど、このUpメソッドでテーブルを作成しているんですね。

###依存関係挿入に登録されるコンテキスト
MSDNのチュートリアルの順番に進めると、唐突に「依存関係挿入に登録されるコンテキストを調べる」が出てきます。
何だこれはという感じですが、
>スキャフォールディング ツールによってデータベース コンテキスト context が自動的に作成され、依存関係挿入コンテナーに登録されました。

ということらしい。
長々と書かれていますが、スキャフォールディングではStartup.ConfigureServices メソッドに、モデルとして作成した「Movie」の情報を調整するように追記してくれているみたいです。
そしてもう一つは「Data」フォルダにある RazorPagesMovieContext.cs の話で、RazorPagesMovieContextクラス内で、プロパティが設定されている Movie クラスをデータセットとして扱うことが可能になっているようです。

##4.実行
というわけで実行してみます。F5キーでもIIS Expressボタンでもどちらでも大丈夫です。
![20220222_025.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/82fbaccd-ab59-9949-f7e4-c469f1e7ee3e.png)
とりあえず立ち上がりました。
で、ここから、URLの末尾に「/movies」を加えてページ遷移します。
![20220222_026.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/3bf99dfd-c686-a415-47c6-80104b094693.png)
もし、https://localhost:xxxxx/movies （xxxxxはポート番号）にジャンプしない場合は、一度終了して、ビルドしてから再実行してみて下さい。
※私はジャンプしなかったのでビルドして再実行したら出来ました。

データを登録してみます。
チュートリアルの通りにポチポチと入力。
![20220222_027.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/4ae280b3-e97f-fec0-3eb6-a2dff32fb63c.png)
※コピペ用にテキスト貼っておきます。

- Title：The Good, the bad, and the ugly
- Genre：Western
- Price：1.19

Createボタンをクリックし、登録されていることを確認。
![20220222_028.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/c34f9a79-4aa7-f4b0-3587-84d72504a009.png)

大丈夫そうですね。

#参考
https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/razor-pages/model?view=aspnetcore-2.1&tabs=visual-studio

https://www.fenet.jp/dotnet/column/tool/641/#:%7E:text=ASP.NET%20MVC%E3%81%AEModel%E3%81%A8%E3%81%AF%E3%80%81%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E3%82%84%E3%82%8A%E3%81%A8%E3%82%8A,%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E6%A4%9C%E7%B4%A2%E3%81%97%E3%81%BE%E3%81%99%E3%80%82

https://dotnet.microsoft.com/ja-jp/apps/aspnet/mvc#:~:text=MVC%20%E3%81%AF%E3%80%81%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%20%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%95%E3%82%A7%E3%82%A4%E3%82%B9%20(%E3%83%93%E3%83%A5%E3%83%BC,%E3%81%95%E3%82%8C%E3%82%8B%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%20%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E3%81%A7%E3%81%99%E3%80%82&text=%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9%E3%83%BC%E3%81%AF%E3%80%81%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E3%83%93%E3%83%A5%E3%83%BC,%E3%83%9A%E3%83%BC%E3%82%B8%E3%82%92%E3%83%AC%E3%83%B3%E3%83%80%E3%83%AA%E3%83%B3%E3%82%B0%E3%81%97%E3%81%BE%E3%81%99%E3%80%82

https://codezine.jp/article/detail/7491