プログラムを中心とした個人的なメモ用のブログです。 タイトルは迷走中。
内容の保証はできませんのであしからずご了承ください。

2018/03/27

MVC における ViewModel とは?

update2018/05/15 event_note2018/03/27 2:16

ViewModel と聞くと MVVM パターンを連想します。
しかし、ASP.NET および ASP.NET Core の解説記事において ViewModel という言葉がよく使われており、「MVC パターンで ViewModel ?」とはてなマークがついてしまいました。

いろいろ調べた結果を私なりにまとめてみたいと思います。

一応環境としては ASP.NET Core (現時点のバージョンは 2.0) を前提としています。

MVC における ViewModel とは

ViewModel は、特定の View で使用されるデータモデルを表すクラスです。

Model にあるクラスはドメインモデルであり、View に表示するデータモデルとは必ずしも一致しません。
また、それらには View に表示されないデータなども含まれていたりしますし、View には複数の Model から取得したデータを表示したいことがあります。

ちなみに、ASP.NET Core では View に複数の Model を含めることが出来ません。
例えば、以下のような Model がある場合。

Model

public class Student
{
    public int Id {get; set;}
    public string Name {get; set;}
}

public class Subject
{
    public int SubjectID {get; set;}
    public string SubjectName {get; set;}
}

View に以下のように書くとエラーとなります。

View (Razor)

@model ProjectName.Model.Student
@model ProjectName.Model.Subject

従って、複数の Model のプロパティを View に表示したい場合には、ViewModel を作成する必要があります。

また、ViewModel を作成することで、以下のようなメリットもあります。

  • Model から取得したデータを View 用に整形したり書式設定したりできる
  • Model と View の間のやりとりがシンプルになる
  • View をドメインモデルと切り離して検証できる

ViewModel の作成

命名規則はどうするか?

例えば以下のような命名規則があるようです。

  • {Controller}{Action}ViewModel.cs
  • {Controller}{Action}VM.cs

個人的には省略したくないので、長くなりますが前者のほうが好みです。

尚、ASP.NET Core 2.0 のテンプレートでは、ErrorViewModel.cs というファイルがデフォルトで存在しています。

フォルダ構成はどうするか?

例えば、以下のような配置があるようです。

  • Models フォルダの配下に ViewModel のファイルを配置
  • プロジェクトのルートに ViewModels フォルダを作成し、その配下に ViewModel ファイルを配置

ViewModel は Model に従属しているわけではないと思うので、個人的には後者のほうが好みです。

尚、ASP.NET Core 2.0 のテンプレートでは、Models フォルダの配下に ErrorViewModel.cs がありました。

具体的なコード例

一般的に、ViewModel には View に表示されるデータ(プロパティ)のみが含まれ、それ以外のデータが含まれていてはいけないようです。

前述したコードを ViewModel を使って実装すると以下のようになります。

ViewModel

public class StudentViewModel
{
    public int Id {get; set;}
    public string Name {get; set;}
    public int SubjectID {get; set;}
    public string SubjectName {get; set;}
}

View (Razor)

@model ProjectName.StudentViewModel

また、ViewModel は継承を使って以下のように書くこともできます。

public class StudentViewModel:Subject
{
    public int Id {get; set;}
    public string Name {get; set;}
}

参考 URL