タスク管理ツールをReact + ASP.Coreで作る 06コードファーストアプローチでのDB構築と、データ投入

[前回](https://qiita.com/mosuma/items/246624b5075d92ac528d)の続きです。
今回はDBの構築をやっていきます。


### ガイド
全体Index：[タスク管理ツールをReact + ASP.Coreで作る - Index](https://qiita.com/mosuma/items/88e40dc44e7bff1a54d8)


# データ構造とアプローチ

ASP.NET Coreでデータベースを扱う場合、構築方法は大きく2つの種類があります。一つ目がDBを作成し、DB定義からアプリケーション側にオブジェクトを生成する「データベースファースト」、二つ目が、アプリケーション側にオブジェクトを作り、オブジェクトからDBを生成する「コードファースト」というアプローチです。

今回は「コードファースト」を採用します。
両者のメリットデメリットは今回は割愛しますが、サーバーサイドのプログラムで人手での構築が完結するので、データ構造を作っておけばデータベース構築そのものはエンティティフレームワークが大半やってくれるというのが大きな理由です。





# パッケージ追加の準備とパッケージ追加

DBを使用するにあたり、いくつかのパッケージを追加でインストールする必要があります。
パッケージはコマンドラインからでもインストール可能ですが、今回はNuGet Galleryと呼ばれるGUIからNuGetパッケージの管理を可能にする拡張機能をインストールします。

## NuGet Galleryの追加
拡張機能追加タブに移動し、検索ゾーンに"nuget"と入れると、nuget関連の拡張機能が表示されるので、Nuget Galleryを探してインストールします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664470/774e6421-6815-428b-e4ad-65e8475f4fae.png)


## Nuget Galleryを用いてパッケージを追加する
### Nuget Galleryを開く
インストールが済むと、F1押下またはCtrl+P→Shift+.でNuget Galleryを開くことができるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664470/22747ede-d553-65ef-525a-f0c7d26e4bcf.png)

### パッケージの探し方
Filterに入力することで絞り込みができるので、必要なパッケージを探してインストールします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664470/f8f1cf5f-319d-e504-82f0-a3359056ad15.png)


### 今回インストールするパッケージ一覧
今回は以下のパッケージをインストールします。
今回は.バージョン5をターゲットフレームワークにしているので、バージョン5の中の最新をそれぞれインストールしてあります

- Microsoft.AspNetCore.Identity.EntityFrameworkCore
- Microsoft.EntityFrameworkCore.Design
- Microsoft.EntityFrameworkCore.Sqlite



「Microsoft.AspNetCore.Identity.EntityFrameworkCore」は、認証機能付きでデータを操作するためのパッケージです。
認証機能はまだ使用しませんが、後に実装するときのために今のうちに入れておきます。
「Microsoft.EntityFrameworkCore.Design」はコードファースト関連の機能を使用するときに必要になるパッケージ、「Microsoft.EntityFrameworkCore.Sqlite」はSqliteを使用する際に必要になるパッケージです。

上記のインストールが完了すればパッケージ追加は完了です。




<details><summary>参考：パッケージ追加が成功しているかどうかの確認は以下(開くと表示)</summary><div>

①Nuget Galleryでインストール状態になっているかどうかを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664470/74d78c94-1b47-2c8d-444b-15a8b3dd6975.png)



②プロジェクトファイルを開いて、上記のパッケージが設定されているかどうか
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664470/25beb469-192a-a3ec-b4bc-fd65f5ad69b3.png)



</div></details>

# コードの追加とDBの構築

## コードの追加
パッケージの追加が出来たので、次にコードを追加or変更していきます。

実装するのは以下3ファイルです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664470/54b3d0b7-16d6-5d39-8c73-29fd6be2f027.png)

#### appsettings.json
DBへの接続文字列を追加します。

```diff_json:appsettings.json
{
+  "ConnectionStrings": {
+    "DefaultConnection":"Data Source=database.db"
+  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}
```


#### DataContext.cs

ASP.NET Coreでは、データモデルの操作は「EntityFramework」というフレームワークを用いて行われます。
「データモデル」の具体的な対象には、SQL ServerやMysqlなどの各種DBや、XMLファイルなど様々な種類があります。今回はSqliteを使用します。
コンテキストクラスはEntityFrameworkのクラスの一つで、DBに対してデータ取得・登録・削除などの操作や、DB生成・テーブル変更などの操作をすることができます。
今回は以下の様なコードになります。
「t_task」をテーブルに持つDBというのが簡単な説明になります。
「entity.HasKey(e => new { e.id_task });」の部分が、モデルクラスの段階で出てこなかった主キーの設定になります。

```diff_c_sharp:DataContext.cs
using Microsoft.EntityFrameworkCore;

namespace server_app.Models.EDM
{
    public partial class DataContext : DbContext
    {
        public DataContext(DbContextOptions options) : base(options)
        {
        }

        public DbSet<t_task> t_tasks {get; set;}
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<t_task>(entity =>
            {
                entity.HasKey(e => new { e.id_task });

            });
        }
    }
}
```


#### Startup.cs

Startup.csに、Sqliteの実装で「DataContext」に従ったデータモデルに対する操作の機能を組み込むよ、接続文字列は"DefaultConnection"の定義に従うよという内容を追加します。

```diff_c_sharp:Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
+ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
+ using server_app.Models.EDM;

namespace server_app
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
+            services.AddDbContext<DataContext>(opt =>
+            {
+             opt.UseSqlite(Configuration.GetConnectionString("DefaultConnection"));
+            } );

            services.AddControllers();

```




<details><summary>Startup.cs全体(開くと表示)</summary><div>

```diff_c_sharp:Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
+ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
+ using server_app.Models.EDM;

namespace server_app
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
+            services.AddDbContext<DataContext>(opt =>
+            {
+             opt.UseSqlite(Configuration.GetConnectionString("DefaultConnection"));
+            } );

            services.AddControllers();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "server_app", Version = "v1" });
            });

            
           services.AddCors(o => o.AddPolicy(MyAllowSpecificOrigins, builder =>
           {
               builder.AllowAnyOrigin()    // Allow CORS Recest from all Origin
                      .AllowAnyMethod()    // Allow All Http method
                      .AllowAnyHeader();   // Allow All request header
           }));
        }

        readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "server_app v1"));
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseCors(MyAllowSpecificOrigins);   // Add For CORS

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}



```


</div></details>
これでコードの追加は終了です。
次にDBの生成を行います。

## DBの生成
コードの追加が完了したので、以下のコマンドを実行します。

```
> dotnet ef migrations add initial
> dotnet ef database update
```

マイグレーションが実施され、コンテキストクラスの内容に従いデータベース「database.db」が生成されます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664470/1d9ac00c-fab9-01bd-df99-05ccc9151d08.png)


## DB生成後の状態
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664470/dd04656a-15e4-9b75-f87d-214a66d1af96.png)


## DBの確認・操作
DBの追加が出来たので、内容を確認してみましょう。SQLite拡張機能などで確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664470/f2355408-e200-04fb-f465-1c4c7ec1cdff.png)


開くと、以下の様にDBが構築されていることが分かります。
(Sqliteの実装ではbooleはint、Datetimeは日付で実装されるのですね)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664470/657b8249-123c-c94a-6079-c099055389f7.png)

## ダミーデータの投入

構築したSQLiteのテーブルの内容を用いてデータを表示していきたいのですが、現状テーブルが空です。
登録機能の構築はもう少し先になりそうなので、まずダミーデータを投入していこうと思います。

右クリック→New Queryでクエリウインドウを開きます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664470/45b1dfab-2349-b5bc-490a-9684072f4e64.png)

データインサート用のSQLを作って、右クリックで実行します

```diff_sql
INSERT INTO t_tasks(id_task, title, is_finish, end_date_scheduled) 
 VALUES('e01782d2-4e34-45cc-b101-2118f23bac48', 'title01', 0, '2022-10-27T23:59:40.9458612+09:00');
```

```diff_sql
INSERT INTO t_tasks(id_task, title, is_finish, end_date_scheduled) 
 VALUES('80adddd4-9f92-49f3-b220-dcebc27f40be', 'title02', 1, '2022-10-28T23:59:40.9459392+09:00');
```

上記のSQLをそれぞれ以下の様に実行してデータ追加しました。
(1回のクエリでできるのでしょうけど、SQLiteを直接操作することが今後ない気がするのでやっつけです。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664470/91647006-e112-fdd9-4107-5ffc8000546f.png)


以下の様にデータが追加されていることが確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664470/f1be7ea1-cb4f-358e-82e9-ea1e78211df6.png)


今回は以上です。

続きは[次回](https://qiita.com/mosuma/items/35703e5e435dda9d8f16)です