記事目次
- ASP.NET Core 3.0 Razor Pages 事始め(1) - はじめてのRazor Pagesアプリケーション
- ASP.NET Core 3.0 Razor Pages 事始め(2) - スキャフォールディングとDBマイグレーション
- ASP.NET Core 3.0 Razor Pages 事始め(3) - マイグレーションのやり直しとURLルーティング
- ASP.NET Core 3.0 Razor Pages 事始め(4) - ページモデルとページハンドラ
- ASP.NET Core 3.0 Razor Pages 事始め(5) - Postページハンドラとタグヘルパー
- ASP.NET Core 3.0 Razor Pages 事始め(6) - データベースに初期値を設定する
- ASP.NET Core 3.0 Razor Pages 事始め(7) - Viewの変更とコンカレンシー例外処理
- ASP.NET Core 3.0 Razor Pages 事始め(8) - 検索機能の追加
- ASP.NET Core 3.0 Razor Pages 事始め(9) - ページに新しいフィールドを追加する <-- この記事
- ASP.NET Core 3.0 Razor Pages 事始め(10) - 検証機能の追加
ASP.NET Core 3.0 Razor Pages 事始め(8)の続きです。
今回は公式チュートリアルのASP.NET Core で Razor ページに新しいフィールドを追加するに沿って進めていこうと思います。
モデルへプロパティを追加
それでは、チュートリアルに沿って進めていきます。まず、Movieモデルへ評価を示すプロパティを追加します。
Models/Movie.cs ファイルを開き、Rating プロパティを追加します。
[Display(Name = "レイティング")]
public string Rating { get; set; }
Index.cshtmlを開き、Rating フィールドを追加します。
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
...
<table class="table">
<thead>
<tr>
...
<th>
@Html.DisplayNameFor(model => model.Movies[0].Rating)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Movies) {
<tr>
...
<td>
@Html.DisplayFor(modelItem => item.Rating)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.ID">編集</a> |
<a asp-page="./Details" asp-route-id="@item.ID">詳細</a> |
<a asp-page="./Delete" asp-route-id="@item.ID">削除</a>
</td>
</tr>
}
</tbody>
</table>
Create.cshtmlにも、Ratingのフィールドを追加します。
<div class="form-group">
<label asp-for="Movie.Rating" class="control-label"></label>
<input asp-for="Movie.Rating" class="form-control" />
<span asp-validation-for="Movie.Rating" class="text-danger"></span>
</div>
同様にして、Edit.cshtml, Delete.cshtml, Details.cshtml にもRatingフィールドを追加します。
ビルドして、実行してみます。
しかし、Indexページを開こうとすると、以下の例外が発生してしまいます。
An unhandled exception occurred while processing the request.
SqliteException: SQLite Error 1: 'no such column: m.Rating'.
Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(int rc, sqlite3 db)
これは、データベースのMovie テーブにRatingカラムがまだ存在しないためです。
Code First Migrations
Code First Migrations を利用して、これを解決します。
まず、SeedData
クラスを変更し、Ratingプロパティに値を設定するようにします。
context.Movies.AddRange(
new Movie
{
Title = "When Harry Met Sally",
ReleaseDate = DateTime.Parse("1989-2-12"),
Genre = "Romantic Comedy",
Price = 800M,
Rating = "R",
},
new Movie
{
Title = "Ghostbusters ",
ReleaseDate = DateTime.Parse("1984-3-13"),
Genre = "Comedy",
Price = 900M,
Rating = "G",
},
new Movie
{
Title = "Ghostbusters 2",
ReleaseDate = DateTime.Parse("1986-2-23"),
Genre = "Comedy",
Price =1000M,
Rating = "G",
},
new Movie
{
Title = "Rio Bravo",
ReleaseDate = DateTime.Parse("1959-4-15"),
Genre = "Western",
Price = 500M,
Rating = "NA",
}
);
次のコマンドを実行します。
dotnet ef database drop
dotnet ef migrations add addrating
dotnet ef database update
最初にDBを削除します。これは、SeedDataでのデータ初期化コードを動かすためです。
以下実行結果の抜粋です。
$ dotnet ef database drop
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
Entity Framework Core 3.0.0 initialized 'RazorPagesMovieContext' using provider 'Microsoft.EntityFrameworkCore.Sqlite' with options: None
Are you sure you want to drop the database 'main' on server 'MvcMovie.db'? (y/N)
y
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
Entity Framework Core 3.0.0 initialized 'RazorPagesMovieContext' using provider 'Microsoft.EntityFrameworkCore.Sqlite' with options: None
Dropping database 'main'.
Successfully dropped database 'main'.
$ dotnet ef migrations add addrating
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
Entity Framework Core 3.0.0 initialized 'RazorPagesMovieContext' using provider 'Microsoft.EntityFrameworkCore.Sqlite' with options: None
Done. To undo this action, use 'ef migrations remove'
$ dotnet ef database update
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
Entity Framework Core 3.0.0 initialized 'RazorPagesMovieContext' using provider 'Microsoft.EntityFrameworkCore.Sqlite' with options: None
info: Microsoft.EntityFrameworkCore.Database.Command[20100]
Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30']
PRAGMA journal_mode = 'wal';
Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30']
PRAGMA journal_mode = 'wal';
Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30']
CREATE TABLE "__EFMigrationsHistory" (
"MigrationId" TEXT NOT NULL CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY,
"ProductVersion" TEXT NOT NULL
);
…
Done.
正常に終了しました。
なお、SQLiteの場合、EFはカラムの変更はサポートしていませんでしたが、試した範囲では、
カラムの追加は大丈夫みたいです。dropでDB削除せずに、マイグレーションを行なってみましたが、正常にコマンドが終了しました。
実行してみる
それでは、実行してみます。
うまく動作しました。
新規追加、編集、詳細なども動作するかを確認します。
ところで、この "R"ってなんだろう? 調べたら、Restricted
の頭文字のようです。
R:17歳未満の子供は同伴する保護者または成人の保護者が必要です。
ということらしいです。G, PG, PG-13, R, NC-17 があるらしいです。
サンプルコードで代入されていた NA
は、評価無しということかな。
入力時も小数点以下を表示しないようにする
ここまで書いて気がついたんですが、
[DisplayFormat(DataFormatString ="{0:#,0}")]
public decimal Price { get; set; }
と指定してるのに、編集ページ(Edit.cshtml)では、
小数部が表示されてます。この小数部を表示しないようにするには、ApplyFormatInEditMode
プロパティを使えば良いみたいです。
[DisplayFormat(DataFormatString ="{0:#,0}", ApplyFormatInEditMode = true)]
public decimal Price { get; set; }
これで以下のような表示になりました。
今回はこれでおしまい。いよいよ次回がチュートリアルの最後となります。