新增欄位
注意
本教學課程的更新版本可在此取得,它使用最新版的 Visual Studio。 新的教學課程會使用 ASP.NET Core MVC,它在本教學課程提供多種改良。
本教學課程可讓您了解 ASP.NET Core MVC 與控制器和檢視。 Razor 頁面是 ASP.NET Core 中的新替代方案,它是以頁面為基礎的程式設計模型,可讓 Web UI 的建立更容易且更有效率。 建議您在嘗試使用 MVC 版本之前,先試試 Razor 頁面教學課程。 Razor 頁面教學課程:
- 比較容易學習。
- 涵蓋更多功能。
- 是開發新應用程式的建議方法。
在本節,您會使用 Entity Framework Code First Migrations 將部分變更移轉至模型類別,以便讓變更套用至資料庫。
根據預設,使用 Entity Framework Code First 來自動建立資料庫時 (正如稍早在本教學課程操作的動作),Code First 會將表格新增至資料庫,以協助追蹤資料庫的結構描述是否與它產生的來源模型類別同步。 如果未同步,Entity Framework 會擲回錯誤。 這可讓您更輕鬆地在開發階段追蹤您可能只會在執行階段 (透過不明的錯誤) 發現的問題。
為模型變更設定 Code First Migrations
前往方案總管。 以滑鼠右鍵按一下 Movies.mdf 檔案,然後選取 [刪除] 移除電影資料庫。 如果您沒有看到 Movies.mdf 檔案,請按一下紅色外框下顯示的 [顯示所有檔案] 圖示。
建立應用程式,確認沒有任何錯誤。
在 [工具] 功能表按一下 [NuGet 套件管理員],然後按一下 [套件管理員主控台]。
在「套件管理員主控台」視窗的 PM>
提示中輸入
Enable-Migrations -ContextTypeName MvcMovie.Models.MovieDBContext
Enable-Migrations 命令 (如上所示) 會在新的 Migrations 資料夾中建立 Configuration.cs 檔案。
Visual Studio 會 開啟 Configuration.cs 檔案。 將 Configuration.cs 檔案的 Seed
方法取代為下列程式碼:
protected override void Seed(MvcMovie.Models.MovieDBContext context)
{
context.Movies.AddOrUpdate( i => i.Title,
new Movie
{
Title = "When Harry Met Sally",
ReleaseDate = DateTime.Parse("1989-1-11"),
Genre = "Romantic Comedy",
Price = 7.99M
},
new Movie
{
Title = "Ghostbusters ",
ReleaseDate = DateTime.Parse("1984-3-13"),
Genre = "Comedy",
Price = 8.99M
},
new Movie
{
Title = "Ghostbusters 2",
ReleaseDate = DateTime.Parse("1986-2-23"),
Genre = "Comedy",
Price = 9.99M
},
new Movie
{
Title = "Rio Bravo",
ReleaseDate = DateTime.Parse("1959-4-15"),
Genre = "Western",
Price = 3.99M
}
);
}
將滑鼠停留在 Movie
下的紅色曲線,按一下 Show Potential Fixes
,然後按一下 [using] [MvcMovie.Models;]
這樣做會新增下列 using 陳述式:
using MvcMovie.Models;
注意
Code First Migrations 會在每次移轉後 (也就是在套件管理員主控台呼叫 update-database) 呼叫 Seed
方法,且此方法會更新已插入的列,如果列尚不存在則直接插入。
下列程式碼中的 AddOrUpdate 方法會執行「upsert」作業:
context.Movies.AddOrUpdate(i => i.Title,
new Movie
{
Title = "When Harry Met Sally",
ReleaseDate = DateTime.Parse("1989-1-11"),
Genre = "Romantic Comedy",
Rating = "PG",
Price = 7.99M
}
因為 Seed 方法在每次移轉時都會執行,您不只能插入資料,因為您嘗試新增的列在建立資料庫的第一次移轉後就已經存在。 「upsert」作業會防止您嘗試插入已存在的列時會發生的錯誤,但會覆寫您在測試應用程式時可能已完成的任何資料變更。 表格中有測試資料時,您可能不希望發生上述情況:某些案例中,如果您在測試時變更資料,可能會希望資料庫更新後變更仍保留下來。 這種情況下,應該執行條件式插入作業:只在列不存在時才插入列。
傳遞至 AddOrUpdate 方法的第一個參數會指定要用來檢查列是否存在的屬性。 針對您提供的測試電影資料,您可將 Title
屬性用於此目的,因為清單中的每個標題都不重複:
context.Movies.AddOrUpdate(i => i.Title,
此程式碼會假設每個標題都不重複。 如果您手動新增重複的標題,下次執行移轉時會收到下列例外狀況。
序列中包含多個元素
如需詳細了解 AddOrUpdate 方法,請參閱使用 EF 4.3 AddOrUpdate 方法。
按下 CTRL-SHIFT-B 建立專案。(如果您此時不見例,後續步驟將會失敗。)
下個步驟是建立初始移轉的 DbMigration
類別。 此移轉會建立新的資料庫,這也就是您在上一個步驟要刪除 movie.mdf 檔案的原因。
在 [套件管理員主控台] 視窗輸入命令 add-migration Initial
以建立初始移轉。 「Initial」是用來命名已建立的移轉檔案的任意名稱。
Code First Migrations 會在 Migrations 資料夾中建立另一個類別檔案 (名稱為 {DateStamp}_Initial.cs),且此類別包含的程式碼會建立資料庫結構描述。 移轉檔案名稱的前綴包含時間戳記,有助排序。 檢查 {DateStamp}_Initial.cs檔案,其中包為電影資料庫建立 Movies
表格的指示。 如果您在下方指示更新資料庫,此 {DateStamp}_Initial.cs 檔案就會執行並建立資料庫結構描述。 然後,Seed 方法會執行以便在資料庫填入測試資料。
在「套件管理員主控台」輸入命令 update-database
以建立資料庫並執行 Seed
方法。
如果您收到錯誤,指出表格已存在且無法建立,可能是因為您在刪除資料庫之後及執行 update-database
之前執行應用程式。 在此情況下,請再次刪除 Movies.mdf 檔案,然後重試 update-database
命令。 如果仍然收到錯誤,請刪除移轉資料夾和內容,然後開始操作此頁面頂端的指示 (也就是刪除 Movies.mdf 檔案,然後繼續啟用移轉)。 如果仍然收到錯誤,請開啟 SQL Server 物件總管並從清單中移除資料庫。 如果您收到錯誤,指出「無法將檔案 .mdf 附加為資料庫」,請將 web.config 檔案連接字串裡的 Initial Catalog 屬性移除。
執行應用程式,並前往 /Movies URL。 Seed 資料隨即顯示。
將 Rating 屬性新增至電影模型
首先,新增 Rating
屬性至現有的 Movie
類別。 開啟 Models\Movie.cs 檔案並新增 Rating
屬性,如下所示:
public string Rating { get; set; }
完成的 Movie
類別至此看起來類似下列程式碼:
public class Movie
{
public int ID { get; set; }
public string Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
public decimal Price { get; set; }
public string Rating { get; set; }
}
建立應用程式 (Ctrl+Shift+B)。
因為您已將欄位新增至 Movie
類別,所以也需要更新繫結允許清單,才能加入這個新屬性。 更新Create
的 bind
屬性和 Edit
動作方法,以便加入 Rating
屬性:
[Bind(Include = "ID,Title,ReleaseDate,Genre,Price,Rating")]
您也需要更新檢視範本,以便在瀏覽器檢視中顯示、建立和編輯新的 Rating
屬性。
開啟 \Views\Movies\Index.cshtml 檔案,並在 Price 欄後方新增 <th>Rating</th>
欄標題。 然後,在範本結尾附近新增數 <td>
欄來轉譯 @item.Rating
值。 以下為 Index.cshtml 檢視範本更新後的外觀:
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
@using (Html.BeginForm("Index", "Movies", FormMethod.Get))
{
<p>
Genre: @Html.DropDownList("movieGenre", "All")
Title: @Html.TextBox("SearchString")
<input type="submit" value="Filter" />
</p>
}
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Price)
</th>
<th>
@Html.DisplayNameFor(model => model.Rating)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
@Html.DisplayFor(modelItem => item.Rating)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
@Html.ActionLink("Details", "Details", new { id=item.ID }) |
@Html.ActionLink("Delete", "Delete", new { id=item.ID })
</td>
</tr>
}
</table>
接下來,開啟 \Views\Movies\Create.cshtml 檔案,然後新增 Rating
欄位,當中包含下列醒目顯示的標記。 這個動作可呈現文字方塊,以便您在建立新電影時指定評分。
<div class="form-group">
@Html.LabelFor(model => model.Price, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Price, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Rating, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Rating, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Rating, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
您現在已更新了應用程式的程式碼,藉此支援新的 Rating
屬性。
執行應用程式,並前往 /Movies URL。 不過執行此操作,您會看到下列其中一個錯誤:
建立資料庫後,支援「MovieDBContext」內容的模型已變更。 請考慮使用 Code First 移轉來更新資料庫」(https://go.microsoft.com/fwlink/?LinkId=238269)。
您會看到此錯誤是因為應用程式中更新的 Movie
模型類別現在已與現有資料庫的 Movie
表格的結構描述不同。 (資料庫資料表中沒有任何 Rating
資料行)。
有幾個方法可以解決這個錯誤:
- 讓 Entity Framework 自動卸除資料庫,並重新依據新的模型類別結構描述來建立資料庫。 在開發週期早期,當您在測試資料庫上進行開發時,這個方法會很方便;其可讓您一併調整模型和資料庫結構描述,更加快速。 不過,這麼做的缺點是您會遺失資料庫現有的資料,因此不建議對生產資料庫使用此方法! 使用初始設定式將測試資料自動植入資料庫,通常是開發應用程式的有效方式。 如需 Entity Framework 資料庫初始設定式的詳細資訊,請參閱 ASP.NET MVC/Entity Framework 教學課程。
- 您可明確修改現有資料庫的結構描述,使其符合模型類別。 這種方法的優點是可以保留您的資料。 您可以手動方式或藉由建立資料庫變更指令碼來進行這項變更。
- 使用 Code First 移轉來更新資料庫結構描述。
在本教學課程中,我們將使用 Code First 移轉。
更新 Seed 方法,讓它為新的欄提供值。 開啟 Migrations\Configuration.cs 檔案,並將 Rating 欄位新增至每個 Movie 物件。
new Movie
{
Title = "When Harry Met Sally",
ReleaseDate = DateTime.Parse("1989-1-11"),
Genre = "Romantic Comedy",
Rating = "PG",
Price = 7.99M
},
建立解決方案,然後開啟「套件管理員主控台」視窗,輸入下列命令:
add-migration Rating
add-migration
命令會告知移轉架構,檢查目前的電影模型與目前的電影資料庫結構描述,並建立必要的程式碼以將資料庫移轉至新的模型。 Rating 是用來命名移轉檔案的任意名稱。 在移轉步驟使用有意義的名稱會更加實用。
此命令完成時,Visual Studio 會開啟類別檔案來定義新的 DbMigration
衍生類別,並在 Up
方法顯示用於建立新欄的程式碼。
public partial class AddRatingMig : DbMigration
{
public override void Up()
{
AddColumn("dbo.Movies", "Rating", c => c.String());
}
public override void Down()
{
DropColumn("dbo.Movies", "Rating");
}
}
建立解決方案,然後在套裝管理員主控台視窗輸入 update-database
命令。
下圖顯示套件管理員主控台視窗的輸出 (日期戳記前的 Rating 將會不同。)
重新執行應用程式,並前往 /Movies URL。 您可以看到新的「Rating」欄位。
按一下 [新建] 連結以新增新電影。 請注意,您已可以新增評分。
按一下 [建立]。 新的電影 (包括評分) 現在會在電影清單中顯示:
既然專案已在使用移轉,您在新增欄位或更新結構描述時就不需要刪除資料庫了。 在下一節,我們會進行更多結構描述變更,並使用移轉來更新資料庫。
您也應將 Rating
欄位新增至 Edit、Details 和 Delete 檢視範本。
您可以再次在「套件管理員主控台」視窗輸入「update-database」命令,不會有任何移轉程式碼執行,因為結構描述符合模型。 不過,執行「update-database」會再次執行 Seed
方法,如果您變更任何 Seed 資料,則變更將會遺失,因為 Seed
方法會更新並插入資料。 您可以在 Tom Dykstra 熱門的 ASP.NET MVC/Entity Framework 教學課程深入瞭解 Seed
方法。
在本節中,您已瞭解如何修改模型物件,並讓資料庫與變更維持同步。 您也已透過範例資料的試用案例瞭解如何填入新建的資料庫。 本節只是 Code First 的快速簡介,請參閱為 ASP.NET MVC 應用程式 建立 Entity Framework 資料模型,針對本主題取得更完整的教學課程。 接下來,我們會說明如何將更豐富的驗證邏輯新增至模型類別,並啟用某些可強制執行的商務規則。