【C#/Blazor】実務Webアプリ開発編 (13)データモデルを設計する ~エンティティと関連を定義する~
この記事は、実務Webアプリ開発編の一記事です。前回の「システム構成を設計する」では、アプリ全体の構成要素と役割の分け方を整理しました。
今回は、要件定義とシステム構成の結果を踏まえて、MentorApp の データモデル をどう設計するかを見ていきます。
「エンティティ」と「関連」をどう定義し、次の画面設計にどうつなげていくかを整理していきましょう。
以下のような方に役立つ内容となっています。
- データベース設計で、まず何から整理すればよいか迷っている
- エンティティと関連の考え方を実例ベースで学びたい
- どれをエンティティにすればよいか、分け方の判断基準がつかめていない
題材として、MentorApp を使って進めます。

GitHubにドキュメント・コードの一式があります。
今回、spec.md におけるデータモデルをみていきます。
User / Mentorship / Topic / Message の4つが、どういう意味を持ち、どうつながっているかを一緒に整理していきましょう。
アプリが動くたびに、データは蓄積・参照・更新が繰り返されます。最初の設計が後々まで影響するため、ここを丁寧に整理しておく価値があります。
データモデルがはっきりすると、画面設計や実装でも迷いにくくなります。一緒に整理していきましょう。
データモデル設計でやること
前回のシステム構成では、データの永続化に EF Core(コードファースト)を用いたリレーショナルデータベース(RDB)を採用しました。
今回はその前提に立ち、ER図(エンティティと関連)をベースに概念レベルのデータモデルを整理していきます。
データモデルとは、アプリが扱う情報を「管理対象となるもの(エンティティ)」と「どう関係するか(関連/リレーションシップ)」で整理したものです。
データモデルは、テーブル設計やコード上のクラス設計の土台になります。
データモデル設計では、画面でユーザーに表示したい情報をそのまま並べるのではなく、業務の中で意味のある単位に分けて考えることがポイントです。
最初にエンティティの境界を整理しておくと、後の画面設計でも「この画面で何のデータを表示するか」がスムーズに決められるようになります。
MentorApp では、メンターとメンティーの関係、相談トピック、メッセージ履歴を扱います。これを4つのエンティティに分けています。
- 何を管理するか:User / Mentorship / Topic / Message の4種類に整理する
- どうつながるか:1対多の関連(1つの親に複数の子がぶら下がる構造)で、メンター・メンティーの関係やそこでの会話の文脈を辿れるようにする
- なぜ分けるか:人・関係・話題・発言がそれぞれ異なる意味と役割を持ち、混在させると管理しにくくなるため
次に、一緒に設計ドキュメントをみながら、MentorAppの具体的なデータモデル設計についてみていきましょう!
MentorAppのspec.mdを読む
要件定義では、ユーザーロール(Admin / Mentor / Mentee)、メンターとメンティーのペアリング、テーマ別の相談管理といった機能要件を整理しました。
さらにシステム構成では、認証に外部IdP(Google認証やMicrosoft Entra Id)を利用することを決めました。データモデルは、それらの要件と構成を前提に設計します。
MentorApp のspec.mdでは、5. データモデル に4つのエンティティと関連がまとめられています。
ここでは、まずデータモデルの定義(ER図・フィールド・具体例)を確認し、続いて設計上のポイントを解説していきます。
エンティティと関連(ER図)
spec.md では、4つのエンティティとその関連を Mermaid の ER図で定義しています。まず全体像を押さえておきましょう。

- User は Mentorship に Mentor としても Mentee としても関連する
- Mentorship は複数の Topic を持つ
- Topic は複数の Message を持つ
各エンティティのフィールド
各エンティティが持つフィールドを確認しておきましょう。それぞれの役割と保持する情報の意味を整理します。
User(ユーザー) システムを利用するアカウント。ロール(Admin / Mentor / Mentee)により権限が異なる。
- Id
- ExternalId(IdPのsub)
- DisplayName
- Email(IdPから取得)
- Role(Admin / Mentor / Mentee)
- CreatedAt
Mentorship(メンタリング関係) Mentor と Mentee のペアリング関係。管理者が作成し、ステータスで進行状態を管理する。
- Id
- MentorUserId → User
- MenteeUserId → User
- Status(Active / Completed / Cancelled)
- StartedAt
- EndedAt(任意)
Topic(相談トピック) Mentorship 内の個別の相談テーマ。Open / Closed のステータスで管理する。
- Id
- MentorshipId → Mentorship
- Title
- Status(Open / Closed)
- CreatedAt
Message(メッセージ) Topic 内のチャットメッセージ。追記のみ(編集・削除なし)。
- Id
- TopicId → Topic
- SenderUserId → User
- Content
- SentAt
具体例
定義だけでは抽象的なので、具体的なデータでイメージを補いましょう。
ここでは「メンターの鈴木さんとメンティーの田中さんがペアになり、転職相談と学習計画について会話している」状況を例にします。
User
| Id | ExternalId | DisplayName | Role | |
|---|---|---|---|---|
| 1 | entraid-abc123 | 鈴木 太郎 | suzuki@example.com | Mentor |
| 2 | entraid-def456 | 田中 花子 | tanaka@example.com | Mentee |
Mentorship
| Id | MentorUserId | MenteeUserId | Status | StartedAt | EndedAt |
|---|---|---|---|---|---|
| 1 | 1 | 2 | Active | 2026-01-10 | null |
Topic
| Id | MentorshipId | Title | Status |
|---|---|---|---|
| 1 | 1 | 転職相談 | Open |
| 2 | 1 | 学習計画 | Closed |
Message
| Id | TopicId | SenderUserId | Content | SentAt |
|---|---|---|---|---|
| 1 | 1 | 2 | 今の会社を辞めて転職を考えています | 2026-01-15 10:00 |
| 2 | 1 | 1 | まず履歴書を整理しましょう | 2026-01-15 10:30 |
| 3 | 2 | 2 | 週10時間の学習計画を立てたいです | 2026-01-20 09:00 |
この4テーブルで、人(User)→ 関係(Mentorship)→ 話題(Topic)→ 発言(Message) の順に文脈が積み上がっているのが分かります。
IDで連鎖しているため、「鈴木さんと田中さんの転職相談での田中さんの発言」を一意に辿れます。
設計上の判断ポイント
ポイント①:「人」と「関係」を別エンティティにする
MentorApp では、User(アカウント)と Mentorship(ペアリング関係)を別エンティティにしています。
もし User 側に「相手ユーザーのID」や「関係の状態」まで持たせた設計にすると、
- 一人のメンターが複数のメンティーを担当する場合にフィールドを増やすか
- User レコードを複数作るか
という構造的な問題が生じます。
Mentorship を独立したエンティティにすることで、ペアリングの数だけ Mentorship レコードを追加するだけで済むようになります。
User レコードには手を加えず、過去のペアリング履歴もデータとして自然に残ります。
User に「相手ユーザーのID」や「関係の状態」まで持たせる設計はよくないってことだね…。
そうですね。「こうしなかったらどうなるか」を考えることが、設計判断を言語化するときの手がかりになります。
なお、User に ExternalId(外部IdPのユーザーID)を持たせているのは、認証に外部IdPを使うと決めたからです。
IdP 側に認証情報を委ね、アプリ側では自前の Id で管理することで、IdP の違いを吸収できます。
ポイント②:会話を話題単位で区切る
Topic を設けることで、Mentorship 内の相談テーマごとに状態を独立して管理できます。「転職相談は終了、学習計画は継続中」のような状態を自然に表現できます。
Topic を設けず Mentorship 直下に Message を並べた場合、全発言がフラットに積み重なり、どこからどこまでが一つの相談かを追いにくくなります。
また「この話題は解決済み」という区切りをデータで表現する手段もなくなります。
Topic がないと Message が全部フラットに並んで、どこからどこまでが一つの相談か分からなくなりそう。
そうです。テーマごとに Status を持てるのも、Topic を独立させたからこそです。
Mentorship 全体が続いていても、終わった話題は Closed にできます。
データモデル設計は画面設計の前に行うことが多いです。
ただ、「各機能の画面で何を表示するか」を意識しながら進めるため、互いに影響しあい、設計の途中で行き来しながら固めていくことも珍しくありません。
データモデルは単なる保存先ではなく、画面・権限・業務ルールの共通土台なのです。
まとめ
- データモデルの役割:管理する情報の単位と関連を整理すること
- MentorAppの4エンティティ:User / Mentorship / Topic / Message の役割を分けていること
- 設計上のポイント:人、関係、話題、発言の責務を混ぜずに履歴と文脈を保つこと
データモデルは、アプリの情報をきれいに保存するためだけでなく、業務のルールを整理するための設計でもあります。
4つのエンティティの役割を分けておくことで、あとから画面や実装を考えるときも筋道が通りやすくなります。
次回は、このデータモデルを踏まえて、画面一覧・画面遷移・アクセス制御をどう設計するかを見ていきます。
データモデルは、画面にも実装にもつながる設計の土台です。引き続き、画面設計とUI設計について一緒に学んでいきましょう!





