はじめに
この記事は、小規模な Web アプリケーション開発において、
私が実際に採用している設計の考え方を整理した連載の一部です。
大規模アーキテクチャや厳密な DDD を前提にせず、
「最初はシンプルに作り、破綻しそうになったら層を分ける」
という現場判断を重視しています。
C#でWebアプリケーションを開発する際、MVC構造は一般的ですが、
Entity / Model / Controller の責務が曖昧になりがちです。
本記事では、その前提のもとで
Entity / Model / MVC の役割と関心ごとを整理します。
1. 層構造の概要
私のソリューションでは以下のプロジェクト構成です:
[ Entity Project ]
├─ Context (Scaffolded)
├─ Entity (Scaffolded)
├─ Entity.Command
├─ Entity.Query
└─ Entity.Utility
[ Web (MVC) Project ]
├─ wwwroot
├─ Model
├─ Model.Utility
├─ Controller
├─ View
└─ ViewModel
Entity群
- DBテーブルをスキャフォールディングで自動生成
- DbContextを含む
- ビジネスルールやデータの読み方・変換を拡張メソッドで付与
- 拡張メソッドはCommand / Query / Utility に分けて実装
- DB更新や状態変更の最終責務を持つ
(ControllerやModelは「判断」までで、実際の変更はEntity側に寄せる)
※ Entityに直接メソッドを持たせないことで、
将来の再スキャフォールディングを耐えられるようにしています
Model / Model拡張メソッド
- Entityの詰め替えやアプリ依存DTOとして扱う
- Entity群と同様にメソッドは Utility に分けて実装
- View向けのデータ加工もここで対応する場合あり
- 業務ルールの判断や状態変更は行わない
- Model.Utility では、Webアプリ固有の整形や変換のみを扱う
※ Controllerを肥大化させないための受け皿として使っています
MVCプロジェクト
- Controller / View / ViewModel
- ViewModelはページ単位で作成
- 簡易ページは ViewBagでデータを渡すだけの場合もあり
※ まずは作業スピードを優先し、後から分離できる余地を残します
この構成を採用している前提は以下です。
- CRUD中心で業務ルールが比較的単純
- 画面数が少なく、Controllerがまだ肥大化していない
- 将来的に分離できるよう、名前空間だけは先に分けている
2. 層ごとの関心ごと
以下は、実装時に「ここに書くべきか?」と迷った際の判断基準として整理したものです。
| 層 | 主な役割 | 気にすること | 気にしなくてよいこと |
|---|---|---|---|
| View / ViewModel | 画面表示 | 表示形式、ユーザー入力の受け渡し | DBアクセス、業務ロジック |
| Controller | ユースケース層相当(小規模案件) | 入力受付、View返却、簡単な業務フロー | 複雑な業務ルール、Entityの内部状態管理 |
| Model / Model拡張メソッド | アプリケーション層 | Entity操作の呼び出し、DTO詰め替え | 業務ルールの判断、状態変更 |
| Entity / Entity拡張メソッド | ドメイン層 | ビジネスルール、データ変換・読み方 | UI表示、業務フロー全体、外部呼び出し |
| DbContext / DB | インフラ層 | データ永続化、トランザクション | 業務ロジック、UI |
3. 層構造の図(現状イメージ)
View / ViewModel ← プレゼンテーション層
↓
Controller ← ユースケース層相当(小規模案件)
↓
Model / Model拡張メソッド ← アプリケーション層
↓
Entity / Entity拡張メソッド ← ドメイン層
↓
DbContext / DB ← インフラ層
- Controllerに簡単な業務フローを含めても小規模案件では問題なし
- Model/Entity拡張メソッドでDBアクセスや変換を整理
- 各層の「何を気にするか・気にしないか」を意識すると責務がぶれない
4. まとめ
- 小規模案件では、Controllerに業務フローが混在していても十分
- Entity拡張メソッドを Command / Query / Utility に分けることで責務を整理
- 将来的に業務フローが複雑化した場合、
ControllerからUseCase層を切り出す方針で拡張可能 - 名前空間やフォルダで責務を分離しておくと、段階的な層拡張もスムーズ
💡 ポイント
- 各層の「関心ごと」を意識する
- 層構造の整理は、小規模案件でも設計理解や保守性の向上に役立つ