ASP.NET Core 3.1 RazorPagesで工数管理アプリを作ってみる②-マスタ管理編

#ASP.NET Core 3.1 RazorPagesでマスタ管理機能を作る
前回の投稿でおおまかな設計が完了したので、今回からは早速コーディングに入っていきます。
まずはマスタ管理機能を作って ASP.NET Core 3.1 RazorPages のお作法とかを学んでいきたいと思います。
テーマは次の通りとします！

・Azure SQL DataBaseを使う
・**スキャフォールディング機能でできるだけ省力化**

#まずは ASP.NET Core 3.1 RazorPages を触ってみる
公式ページのチュートリアルを参考に一通り触ってみます。
[チュートリアル: ASP.NET Core で Razor ページ Web アプリを作成する](https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/razor-pages/?view=aspnetcore-3.1)
これで ASP.NET Core 3.1 RazorPages の大まかな部分は理解できました。
正直初めはとっつきにくいな～と思ってたのですが、実際に触ってみるとこのドキュメントめっちゃわかりやすかったです。

#DB周りをもう少し深堀する
ただ、上記チュートリアルだけではDB操作周り(特に正規化されたテーブルの扱い)について色々疑問が残ったので、別のチュートリアルも触ってみました。
[ASP.NET Core での Entity Framework Core を使用した Razor ページ](https://docs.microsoft.com/ja-jp/aspnet/core/data/ef-rp/intro?view=aspnetcore-3.1&tabs=visual-studio)

特に
 ・複合データモデルの作成 - [ASP.NET Core の Razor ページと EF Core - データ モデル - 5/8](https://docs.microsoft.com/ja-jp/aspnet/core/data/ef-rp/complex-data-model?view=aspnetcore-3.1&tabs=visual-studio)
 ・関連データの読み取り - [ASP.NET Core の Razor ページと EF Core - 関連データの読み込み - 6/8](https://docs.microsoft.com/ja-jp/aspnet/core/data/ef-rp/read-related-data?view=aspnetcore-3.1&tabs=visual-studio)

のあたりを実際に試しました。

#実際にWEBアプリを作っていく
何となく概要がつかめてきたので早速前回設計したデータモデルで開発してみたいと思います。
まずは、PJマスタとPJタスクマスタを管理する画面を作っていきます。

##DBの準備
先に Azure SQL DataBase の準備をします。

##Razor ページ Web アプリを作成する
VS code を開き、ターミナルで任意の場所に移動してから下記コマンドを実行します。

```
dotnet new webapp -o KosuM
code -r KosuM
```

##データモデルの追加
Models という名前のフォルダーを追加します。
Project.csというファイルを追加し、下記の通り記載します。

```C#:Project.cs
namespace KosuM.Models
{
    public class Project
    {
        public int ProjectID { get; set; }

        [Required]
        [StringLength(50)]
        [Display(Name = "プロジェクト名")]
        public string ProjectName { get; set; }

        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        [Display(Name = "プロジェクト開始日時")]
        public DateTime ProjectStartDate { get; set; }

        [Required]
        [StringLength(500)]
        [Display(Name = "備考")]
        public string memo { get; set; }

        public ICollection<ProjectTask> ProjectTasks { get; set; }
    }
}
```

ProjectTask.csというファイルを追加し、下記の通り記載します。

```C#:ProjectTask.cs
namespace KosuM.Models
{
    public class ProjectTask
    {       
        public int ProjectTaskID { get; set; }
        
        public int ProjectID { get; set; }
        
        [Required]
        [StringLength(50)]
        [Display(Name = "作業名")]
        public string ProjectTaskName { get; set; }

        public Project Project { get; set; }       
    }
}
```

##データベース コンテキストクラスの追加
Data という名前のフォルダーを追加します。 
KosuMContext.csというファイルを追加し、下記の通り記載します。

```C#:KosuMContext.cs
namespace KosuM.Data
{
    public class KosuMContext : DbContext
    {
        public KosuMContext (
            DbContextOptions<KosuMContext> options)
            : base(options)
        {
        }

        public DbSet<KosuM.Models.Project> Project { get; set; }
        public DbSet<KosuM.Models.ProjectTask> ProjectTask { get; set; }
    }
}
```

##データベース接続文字列の追加
appsettings.json ファイルに接続文字列を追加して下記に様に変更します。

```json:appsettings.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "KosuMContext": "Data Source= ★接続文字列★"
}
```

##EFツールの追加
プロジェクトにEFツールを追加します。
VS code のターミナルで下記コマンドを実行します。

```
dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
```
##データベース コンテキストの登録
Startup.cs の先頭に次の using ステートメントを追加します。

```C#:Startup.cs
using KosuM.Data;
using Microsoft.EntityFrameworkCore;
```

Startup.ConfigureServices でデータベース コンテキストを登録します。

```C#:Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();

    services.AddDbContext<RazorPagesMovieContext>(options =>
        options.UseSqlite(Configuration.GetConnectionString("KosuMContext")));
}
```

ここまで来たら一回ビルドしてみてエラーが出ない事を確認します。

##スキャフォールディング
スキャフォールディング ツールをインストールします。
VS code のターミナルで下記コマンドを実行します。

```
dotnet tool install --global dotnet-aspnet-codegenerator
```
チュートリアルとかやっていればすでにインストールされていますというエラーが出るはず。

次にVS code のターミナルで下記コマンドを実行します。

```
dotnet aspnet-codegenerator razorpage -m ProjectTask -dc KosuMContext -udl -outDir Pages\ProjectTasks --referenceScriptLibraries
```

これでPJタスクマスタのCRUD画面が出来上がるはず。
初め -outDir でPages\ProjectTask としていたところ出来上がったコードで ProjectTask というページの名前空間とDBコンテキストのクラス名が競合していました。。。しょうもないですがちょっと躓いたので今後注意が必要です。。。

PJマスタについても同様に画面を作ります。

```
dotnet aspnet-codegenerator razorpage -m Project -dc KosuMContext -udl -outDir Pages\Projects --referenceScriptLibraries
```
##画面の確認
ここまで来ると、プロジェクトを登録してそのプロジェクトに対応する作業を登録することができました。

###PJマスタ管理
![KosuM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489752/51dad853-9c8d-330a-e7b4-1c62ab7df3f9.png)
![KosuM2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489752/91f0985e-e6db-96c3-aefd-2d700109d213.png)
![KosuM3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489752/04b62dfc-6410-c87d-31f8-e8eec4c933fd.png
)

###PJタスクマスタ管理
![KosuM4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489752/f71386c8-191e-77e2-db0e-9e1542955b47.png)
![KosuM5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489752/3aee27b2-2760-89df-0ae7-e8e8c5de5065.png)
![KosuM6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489752/965d12f3-ad74-4ada-7726-3d0291014e61.png)

とりあえずこれで簡単なマスタ管理ができるようになりました。
ただ、PJタスクマスタ管理のリスト画面の一覧項目は現状だと

|作業名|Project|
|:-----------------|:------------------|
| 作業A|テストプロジェクト その１ |
| 作業B|テストプロジェクト その１ |
| ・・・|・・・|

という表示になっていて少し見にくいです。

|プロジェクト名|作業名|
|:-----------------|:------------------|
|テストプロジェクト その１ | 作業A|
|テストプロジェクト その１ | 作業B|
| ・・・|・・・|

せめてこの様な表示にするためにモデルを下記の通り変更してみてもう一回スキャフォールディングしてみました。

```C#:ProjectTask.cs
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace KosuM.Models
{
    public class ProjectTask
    {
        [Display(Name = "プロジェクト名")]
        public Project Project { get; set; }
        
        public int ProjectTaskID { get; set; }
        
        public int ProjectID { get; set; }
        
        [Required]
        [StringLength(50)]
        [Display(Name = "作業名")]
        public string ProjectTaskName { get; set; }       
    }
}
```

単純にプロパティの定義の順番を入れ替えて、外部参照のプロパティの表示名を変えただけなのですが下記の通りだいぶ見やすくなったのではないかと思います。
![KosuM7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489752/e2b53dad-563b-6cff-62e9-d3231985a6dc.png)

**スキャフォールディングで作っていくときはモデルのプロパティの定義の順番や表示名まで考える必要がありそうですね。**
ただ、スキャフォールディングは名前の通りあくまで骨組みで見た目や操作性が武骨すぎるので、追々デザインや操作性の向上を図っていきたいと思います。

#マスタ管理はスキャフォールディングをうまく使っていけば効率よくできそうな事がわかってきた
個人的に今までスキャフォールディングの様なコード自動生成についてはあまり良いイメージが無かったのですが、実際に触ってみると意外と良さそうな雰囲気だと思いました。今後、カスタマイズ含めてやってみるとかなりの工数削減になりそうかなと思います！

次回はログイン周りを触ってみたいと思います！