情報応用演習Ⅰ(2024)

【T9b】簡易ブログソフトウェアの作成 Part.Ⅱ ~ 記事関連機能の実装(4/11)

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

9b-4. 「記事」のためのモデルクラスの作成

まずは「記事」に対応するモデルクラスを作成しよう.この「記事」の情報には_に示す項目を含めることにする.

「記事」の情報
項目名必須/任意データ型備考
ID必須整数記事のID(主キー).
タイトル必須文字列記事のタイトル.
本文必須文字列記事の本文.
作成日時必須日付時刻記事を作成した日時.
更新日時必須日付時刻記事を最後に更新した日時.
公開状態必須列挙型記事の更改状態.下書き(非公開)か公開済みかのいずれか.

この「記事」に対応するモデルクラスを定義しよう.クラス名はArticle(あーてぃくる)とする. まずプロジェクト内の Models フォルダを右クリックし,「追加」→「クラス」をクリックする. 作成するクラス名を訊かれるのでArticle(.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
35
36
37
38
39
40
41
42
43
using System.ComponentModel.DataAnnotations; // 追記

namespace T9b.Models
{
    // 「公開状態」を表す列挙型
    public enum PublicationStateType
    {
        [Display(Name = "下書き")]
        Draft,                        // 下書き

        [Display(Name = "公開済み")]
        Published,                    // 公開済み
    }

    // 「記事」クラス
    public class Article
    {
        [Display(Name = "記事ID")]
        public int ArticleId { get; set; }      // 記事ID

        [Display(Name = "タイトル")]
        public string Title { get; set; } = ""; // タイトル

        [Display(Name = "本文")]
        public string Body { get; set; } = "";  // 本文

        [Display(Name = "作成日時")]
        [DataType(DataType.DateTime)]
        public DateTime Created { get; set; }   // 作成日時

        [Display(Name = "更新日時")]
        [DataType(DataType.DateTime)]
        public DateTime Modified { get; set; }  // 更新日時

        [Display(Name = "公開状態")]
        public PublicationStateType PublicationState { get; set; } // 公開状態

        [Display(Name = "著者")]
        public string BlogUserId { get; set; } = ""; // 外部キー(BlogUserのIdを参照)

        public BlogUser? BlogUser { get; set; }      // 参照ナビゲーションプロパティ
    }
}

このArticleクラスは_に示したデータ項目を素直に反映させたクラスとなっている. また,図9a-3-3で示した通り「ユーザー」と「記事」は1対多,別の言い方をすれば 「記事」はいわば「ユーザー」の所有物であるため,「ユーザ」つまりBlogUserクラスへの 必須の (=Null非許容の)外部キーと参照ナビゲーションプロパティを含めている. チュートリアル【T7b】で「必須な(=Null非許容な)外部キープロパティをいきなり追加してはならない」と述べたが,今回は新規にエンティティを 追加するだけ,言い換えればこの変更によって整合性違反となる 既存レコード は発生し得ない( 新規エンティティなのだからテーブルの中身は空 )ので 最初からNull非許容な外部キープロパティをもつエンティティを追加することができる1

この参照ナビゲーションプロパティに合わせてBlogUserクラスにもコレクションナビゲーションプロパティを追加しておこう. Models/BlogUser.cs に_に示す内容を追記する.

BlogUserクラスの追記内容
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// 「ユーザー」クラス
public class BlogUser : IdentityUser
{
    [Display(Name = "ユーザー名")]
    public override string UserName { get => base.UserName; set => base.UserName = value; }

    [Display(Name = "メールアドレス")]
    [EmailAddress]    
    public override string Email { get => base.Email; set => base.Email = value; }

    [Display(Name = "ニックネーム")]
    public string? Nickname { get; set; }

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

    public List<Article>? Articles { get; set; } // コレクションナビゲーションプロパティ
}

Articleクラスがデータベース側に反映されるようにするには,データコンテキストクラスにも手を加える必要がある. Data/T9bContext.cs に_に示す内容を追記しよう.

T9bContextクラスの追記内容
1
2
3
4
5
6
7
8
public class T9bContext : IdentityDbContext<BlogUser>
{
    public T9bContext(DbContextOptions<T9bContext> contextOptions)
        : base(contextOptions)
    { }

    public DbSet<Article> Articles => Set<Article>(); // ←追加
}

ここまで追記ができたらコマンドラインターミナル2_に示すコマンドを 用いてマイグレーションコードの生成とデータベース側への適用を行おう(_).

マイグレーション処理の生成と適用
PS> dotnet ef migrations add AddArticle
PS> dotnet ef database update

実行したら pgAdmin でデータベースの変化も確認しておこう. pgAdmin を起動するか,もしくは pgAdmin がすでに起動中の場合は 「 Servers 」→「 PostgreSQL 16 」→「 Databases 」→「 t9b_db 」→「 Tables 」を右クリックして「 Refresh 」を実行する. t9b_db に,新たなテーブル「 Articles 」が追加されていることを確認する(_).

実行結果

  1. チュートリアル【T7b】では 既にレコードが作成されているテーブル に対して,外部キー制約をもつ必須の(≒NOT NULLな)列を追加したために整合性違反が発生していた.このためエンティティの追加と,それを参照する外部キープロパティの追加にマイグレーションを分割する必要があった.今回は新規にエンティティを作成する,すなわち新たな 空の テーブルを作成するだけであるので,したがって整合性違反となるレコードも発生し得ない.このために今回は必須の外部キープロパティを最初から定義することができる. ↩︎

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

Last updated on 2024-06-19
Published on 2024-06-19

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