在此部分中,Entity Framework Code First 迁移用于:
使用 EF Code First 自动创建数据库时,Code First 将:
__EFMigrationsHistory
表格,以跟踪数据库的架构是否与从生成它的模型类同步。通过自动验证同步的架构/模型可以更容易地发现不一致的数据库/代码问题。
打开 Models/Movie.cs 文件,并添加 Rating
属性:
public class Movie { public int ID { get; set; } public string Title { get; set; } [Display(Name = "Release Date")] [DataType(DataType.Date)] public DateTime ReleaseDate { get; set; } public string Genre { get; set; } [Column(TypeName = "decimal(18, 2)")] public decimal Price { get; set; } public string Rating { get; set; } }
构建应用程序。
编辑 Pages/Movies/Index.cshtml,并添加 Rating
字段:
@page @model RazorPagesMovie.Pages.Movies.IndexModel @{ ViewData["Title"] = "Index"; } <h1>Index</h1> <p> <a asp-page="Create">Create New</a> </p> <form> <p> <select asp-for="MovieGenre" asp-items="Model.Genres"> <option value="">All</option> </select> Title: <input type="text" asp-for="SearchString" /> <input type="submit" value="Filter" /> </p> </form> <table class="table"> <thead> <tr> <th> @Html.DisplayNameFor(model => model.Movie[0].Title) </th> <th> @Html.DisplayNameFor(model => model.Movie[0].ReleaseDate) </th> <th> @Html.DisplayNameFor(model => model.Movie[0].Genre) </th> <th> @Html.DisplayNameFor(model => model.Movie[0].Price) </th> <th> @Html.DisplayNameFor(model => model.Movie[0].Rating) </th> <th></th> </tr> </thead> <tbody> @foreach (var item in Model.Movie) { <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> <a asp-page="./Edit" asp-route-id="@item.ID">Edit</a> | <a asp-page="./Details" asp-route-id="@item.ID">Details</a> | <a asp-page="./Delete" asp-route-id="@item.ID">Delete</a> </td> </tr> } </tbody> </table>
更新以下页面:
Rating
字段添加到“删除”和“详细信息”页面。Rating
字段更新 Create.cshtml。Rating
字段添加到“编辑”页面。在 DB 更新为包括新字段之前,应用将不会正常工作。 在不更新数据库的情况下运行应用会引发 SqlException
:
SqlException: Invalid column name 'Rating'.
SqlException
异常是由于更新的 Movie 模型类与数据库的 Movie 表架构不同导致的。 (数据库表中没有 Rating
列。)
可通过几种方法解决此错误:
让 Entity Framework 自动丢弃并使用新的模型类架构重新创建数据库。 此方法在开发周期早期很方便;通过它可以一起快速改进模型和数据库架构。 此方法的缺点是会导致数据库中的现有数据丢失。 请勿对生产数据库使用此方法! 当架构更改时丢弃数据库并使用初始值设定项以使用测试数据自动设定数据库种子,这通常是开发应用的有效方式。
对现有数据库架构进行显式修改,使它与模型类相匹配。 此方法的优点是可以保留数据。 可以手动或通过创建数据库更改脚本进行此更改。
使用 Code First 迁移更新数据库架构。
对于本教程,请使用 Code First 迁移。
更新 SeedData
类,使它提供新列的值。 示例更改如下所示,但可能需要对每个 new Movie
块做出此更改。
context.Movie.AddRange( new Movie { Title = "When Harry Met Sally", ReleaseDate = DateTime.Parse("1989-2-12"), Genre = "Romantic Comedy", Price = 7.99M, Rating = "R" },
生成解决方案。
从“工具”菜单中,选择“NuGet 包管理器”>“包管理器控制台”。 在 PMC 中,输入以下命令:
Add-Migration Rating Update-Database
Add-Migration
命令会通知框架执行以下操作:
Movie
模型与 Movie
DB 架构进行比较。名称“Rating”是任意的,用于对迁移文件进行命名。 为迁移文件使用有意义的名称是有帮助的。
Update-Database
命令指示框架将架构更改应用到数据库并保留现有数据。
如果删除 DB 中的所有记录,种子初始值设定项会设定 DB 种子,并将包括 Rating
字段。 可以使用浏览器中的删除链接,也可以从 Sql Server 对象资源管理器 (SSOX) 执行此操作。
另一个方案是删除数据库,并使用迁移来重新创建该数据库。 删除 SSOX 中的数据库:
在 SSOX 中选择数据库。
右键单击数据库,并选择“删除”。
检查“关闭现有连接” 。
选择“确定” 。
在 PMC 中更新数据库:
Update-Database
备注
在本教程中,使用 Entity Framework Core 迁移功能(若可行) 。 迁移会更新数据库架构,使其与数据模型中的更改相匹配。 但是,迁移仅能执行 EF Core 提供程序所支持的更改类型,且 SQLite 提供程序的功能将受限。 例如,支持添加列,但不支持删除或更改列。 如果已创建迁移以删除或更改列,则 ef migrations add
命令将成功,但 ef database update
命令会失败。 由于上述限制,本教程不对 SQLite 架构更改使用迁移。 转而在架构更改时,放弃并重新创建数据库。
要绕开 SQLite 限制,可手动写入迁移代码,在表内容更改时重新生成表。 表重新生成涉及:
有关更多信息,请参见以下资源:
删除迁移文件夹。 使用以下命令重新创建数据库。
dotnet ef database drop dotnet ef migrations add InitialCreate dotnet ef database update
运行应用,并验证是否可以创建/编辑/显示具有 Rating
字段的电影。 如果数据库未设定种子,则在 SeedData.Initialize
方法中设置断点。