情報応用演習Ⅰ(2024)

【T5a】モデルとデータベースの連携(前編)(4/5)

プロジェクトタイプASP.NET Core Web アプリ(Model-View-Controller)
プロジェクト名T5a
ソリューション名PIT5
ターゲットフレームワーク.NET 8.0(長期的なサポート)
最上位レベルのステートメントを使用しない使用する(チェックオフ)
注意
  • 本ページの作業内容は 前のページまでの続き になっていることに注意せよ.
    • 先に前のページまでをすべて読み,指示されている作業を済ませてから本ページを読むこと.
    • プロジェクトの作成作業については準備作業を参照せよ.

5a-4. Entity Framework Core を使用するための準備

第02回で Entity Framework Core を用いて,コンソールアプリからリレーショナルデータベースにアクセスする方法を学んだ. チュートリアル【T2e】では,既存のデータベースの テーブルから,それに対応するクラスを自動生成する Database First のアプローチを試みた.本節では逆に モデルクラスの定義からデータベースのテーブル定義を自動生成するCode First(こーど・ふぁーすと)のアプローチを試みる. このためには,以下の手順が必要になる.

  • 【手順】EF Core Code First の使用手順
    1. データコンテキストクラスを定義する.
    2. Program.cs を編集して Entity Framework Core を有効化する.
    3. コマンドラインターミナル1で以下のコマンドを実行する.
      1. dotnet ef migrations add コマンドでマイグレーション(≒データベースへの変更内容をパッケージ化したもの)を生成する.
      2. dotnet ef database update コマンドでデータベースに変更内容を反映する.
      3. (以下,データモデルを変更するたびに dotnet ef migrations adddotnet ef database update を繰り返す.)

まず,データコンテキストクラスを定義しよう.第02回のチュートリアルでも説明したが,そのアプリ内で扱うすべてのモデルクラスのハブとなる クラスである.データベース側にあるデータはこのクラスを通じてアクセスすることになる.たいていの場合,アプリでアクセスする必要があるのは 一つのデータベースのみであるため, データコンテキストクラスはプロジェクトごとに1つ である(複数のデータコンテキストクラスを扱うことも可能である).

各プロジェクトの「データコンテキストクラス」役となるクラスは,DbContextクラス(Microsoft.EntityFrameworkCore名前空間)から派生させる必要がある.今回の「データコンテキストクラス」の名前は,プロジェクト名に合わせてT5aContextという名前のクラスにすることにしよう. プロジェクト内に Data というフォルダを追加し,これを右クリックして「追加」→「クラス」をクリックする. 作成するクラス名を訊かれるのでT5aContext(.csは省略可能)と入力して「追加」ボタンをクリックする. すると空のクラス定義が作られるので_のように書き換えよう.

T5aContextクラスの定義
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
using Microsoft.EntityFrameworkCore; // 追記
using T5a.Models;                    // 追記

namespace T5a.Data
{
    public class T5aContext : DbContext
    {
        public T5aContext(DbContextOptions<T5aContext> contextOptions)
            : base(contextOptions)
        { }

        // ↓これがデータベース上の1つのテーブルに対応する
        public DbSet<Student> Students => Set<Student>();
    }
}

このT5aContextクラスにはDbSet型の プロパティを定義しているが, このクラス内のこの型のプロパティが後にデータベース内の1つのテーブルとして現れる . このクラスはこれ以上何かをする必要はないので,次にデータベース側の準備を行おう. 第02回で説明したようにアプリケーションからデータベースサーバに接続するためには,データベースサーバー側でそのためのユーザーを あらかじめ登録しておく必要がある. 今回は_のような接続ユーザーを登録して使用することにする.

接続のためのユーザー情報
項目
ユーザー名t5a_user
パスワードbX89#TaNNH
管理対象のDB名t5a_db

このような接続ユーザーを登録するためには_に示すSQL文を実行する必要がある.

接続ユーザー登録のためのSQL文
CREATE ROLE "ユーザー名"
  WITH NOSUPERUSER LOGIN CREATEDB
  PASSWORD 'パスワード'

ユーザー名は文字通りユーザー名である.ユーザー名は_のように必ず二重引用符で囲む必要がある. 二重引用符で囲まずとも文法的にはエラーとはならないが,その場合は指定したユーザー名がすべて小文字として認識されるので注意しよう. パスワードもそのままそのユーザーで認証するためのパスワードである.これはSQLの文法上は単なる文字列として記述する 必要があるため,_に示すように単引用符で囲む必要がある.

では_の接続ユーザーを実際に登録してみよう. pgAdmin を起動し, Servers → PostgreSQL 16 → Databases に表示される データベースの一覧から postgres を右クリックし Query Tool をクリックする(_).

SQL文の実行

すると_に示す画面が開くので,_に示すSQL文を実行する(_). 今回は接続ユーザー自身がデータベースそのものの作成も行うので,権限などの設定は必要ない.

ユーザー作成のためのSQL文
1
2
3
CREATE ROLE "t5a_user"
  WITH NOSUPERUSER LOGIN CREATEDB
  PASSWORD 'bX89#TaNNH'

次に Program.cs を編集して,Entity Framework Core を有効化しよう. Program.cs に_に示す内容を追記しよう.

Program.csの追記内容
 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 T5a.Data;                      // 追記

AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); // Npgsqlのための設定(※)

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddDbContext<T5aContext>(opt
    => opt.UseNpgsql(  "..." /* ←ここに接続文字列を含む文字列型の値を置く */ )); 

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();

13行目の.UseNpgsql()メソッドの引数には, 接続文字列 を指定する必要がある.第02回で説明したとおり,接続文字列とは接続先の データベースや認証情報などを含んだ文字列である..UseNpgsql()メソッドの引数に接続文字列を文字列定数として書き込む方法もあるが この方法はセキュリティ的に好ましくない . プログラムを実行中しているあいだ,そのプログラムの実行体は当然のことながらメモリ内に存在している. このメモリダンプ(=実行中のメモリの内容を保存したもの)を取得するのは比較的簡単にできるが,ソースコード上に 認証情報を直接書き込んでしまうとメモリダンプからこれらの情報を取得することができてしまう. また,そもそも 接続先のデータベースはアプリケーションを実行する環境ごとに異なる ため,コードを修正することなく変更できるようにしておいた方が好ましい. このため接続文字列の情報は 設定ファイル に書き込んでおき,これをプログラムの初期化処理で読み込む,という 方法が一般的である.この方法であれば,接続文字列の情報は読み出し時の一時的にしかメモリ上に展開されないためよりセキュアになる. ASP.NET Core では設定ファイルに関する仕組みもあらかじめ用意されている.今回はこの仕組みを利用して 設定ファイルから接続文字列を読み取って使用するように構成してみよう.

ASP.NET Core では汎用的な設定情報はコマンドライン引数や環境変数,設定ファイルなどから取得され,統一的な方法でアクセスすることができる. アプリケーションの設定ファイルとしてもっともよく用いられるのは, プロジェクト内の appsettings.json という名前のファイル である. このファイルはプロジェクト作成時から追加されている(_).

appsettings.json

このファイルはJSON(じぇいそん)と呼ばれるフォーマットのファイルで,データ交換に使用されるフォーマットの一つである. このファイルに接続文字列の情報を書き込んでおくことにしよう. appsettings.json に_に示す内容を追記しよう.

appsettings.jsonへの追記内容
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*", // ←ここカンマを追記するの忘れないように!
  "ConnectionStrings": {
    "T5aContext": "Host=localhost;Port=5432;Username=t5a_user;Database=t5a_db;Password=bX89#TaNNH"
  }
}

設定情報はbuilder変数のConfiguraionプロパティ(IConfigurationインターフェース)から取得することができる.接続文字列を取得するには,このクラスの拡張メソッドGetConnectionString()を使用する. Program.cs の13行目を_に示すように変更しよう.

Program.csメソッドの追記内容
1
2
3
builder.Services.AddDbContext<T5aContext>(
    opt => opt.UseNpgsql(builder.Configuration.GetConnectionString(nameof(T5aContext)))); // 設定からデータコンテキストクラスと
                                                                                          // 同名のキーで登録されている接続文字列を読み出す.

  1. タブのタイトルは「開発用PowerShell」もしくは「Developer PowerShell」となっている. ↩︎

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

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