佳佳的博客
Menu
首页
《.NET Core 实战》 [No.377~378] 迁移实体并生成数据库
Posted by
佳佳
on 2020-04-19
IT
C#
.NET Core
《.NET Core 实战》
读书笔记
<!-- # 《.NET Core 实战》 [No.377~378] 迁移实体并生成数据库 --> <!-- dotnet-core-efcore-migration --> ## 实体模型 实体模型对应数据库中的表,相比普通的类,实体类一般都需要指定主键。在实体类中有三种方法可以指定主键。 1. 名称为 *Id* 或者 *类名 + Id* 的属性会自动被识别为主键; 下面类中的 *CarId* 属性会自动识别为主键。 ```csharp public class Car { public int CarId { get; set; } public string Color { get; set; } } ``` 2. 通过添加 `[Key]` 特性指定主键; 下面类中的 *EmpIdentity* 属性会被识别为主键。 ```csharp public class Employee { [Key] public int EmpIdentity { get; set; } public int EmpAge { get; set; } public int EmpName { get; set; } } ``` 3. 通过在重写 `DbContext` 的 *OnModelCreating* 方法中调用 *HasKey* 方法指定主键。 ```csharp public class Activity { public Guid ActFlag { get; set; } public TimeSpan Period { get; set; } } ``` 在 *OnModelCreating* 方法中指定 *ActFlag* 为主键。 ```csharp public class MyDbContext : DbContext { public DbSet<Car> Cars { get; set; } public DbSet<Employee> Employees { get; set; } public DbSet<Activity> Activities { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Activity>().HasKey(nameof(Activity.ActFlag)); } } ``` ## 迁移(*Migration*)实体到数据库 代码优先的模式下需要根据实体更新数据库,*EntityFrameworkCore* 提供了几个迁移相关的工具以支持这种开发模式。 首先,需要安装 *Microsoft.EntityFrameworkCore.Tools* 工具包,否则话会提示找不到命令。 ```powershell Install-Package Microsoft.EntityFrameworkCore.Tools ``` 成功安装后可以通过 *get-help* 获取 EFCore 的帮助文档。 ```powershell get-help about_EntityFrameworkCore ``` 可以看到除了 *Migration* 相关的命令外,也有根据 DB 生成实体(*entity*)等命令。 ```powershell _/\__ ---==/ \\ ___ ___ |. \|\ | __|| __| | ) \\\ | _| | _| \_/ | //|\\ |___||_| / \\\/\\ TOPIC about_EntityFrameworkCore SHORT DESCRIPTION Provides information about the Entity Framework Core Package Manager Console Tools. LONG DESCRIPTION This topic describes the Entity Framework Core Package Manager Console Tools. See https://docs.efproject.net for information on Entity Framework Core. The following Entity Framework Core commands are available. Cmdlet Description -------------------------- --------------------------------------------------- Add-Migration Adds a new migration. Drop-Database Drops the database. Get-DbContext Gets information about a DbContext type. Remove-Migration Removes the last migration. Scaffold-DbContext Scaffolds a DbContext and entity types for a database. Script-DbContext Generates a SQL script from the current DbContext. Script-Migration Generates a SQL script from migrations. Update-Database Updates the database to a specified migration. SEE ALSO Add-Migration Drop-Database Get-DbContext Remove-Migration Scaffold-DbContext Script-DbContext Script-Migration Update-Database ``` ### Add-Migration 可以通过 *Add-Migration* 命令生成迁移的代码: 语法: ```powershell Add-Migration [-Name] <String> [-OutputDir <String>] [-Context <String>] [-Project <String>] [-StartupProject <String>] [<CommonParameters>] ``` 参数: - *-Name*:指定迁移版本的名称。*-Name* 可以省略不写。 - *-OutputDir*:指定生成的迁移代码保存的目录,默认值是 *Migrations*。 - *-Context*:指定自定义的 *DbContext* 的名字。当项目中存在多个自定义的 *DbContext* 时需要指定使用的 *DbContext* 的名称。 - *-Project*:在VS的程序包管理控制器中执行时,若没有指定该参数,则默认使用程序包管理控制器顶部 **默认项目** 选项中选择的项目。 - *-StartupProject*:指定启动的项目名称。若未指定,则默认使用解决方案中的启动项目。 ```powershell Add-Migration InitialCreate ``` 在本机尝试执行上述命令时出现了 *ScriptHalted* 的错误,同时尝试打开 *工具 → 命令行 → 开发者 PowerShell* 工具时显示了如下错误: > 开发者 PowerShell 需要 PowerShell 3.0 或更高版本。可以从 [https://aka.ms/installpowershell](https://aka.ms/installpowershell) 安装最新版本。 提示 *PowerShell* 版本过低,在上面错误信息的链接中提供了各个版本的安装包的下载地址。 本机环境是 *64位 Win7 SP1*,所以在 [WMF 3.0](https://www.microsoft.com/en-us/download/details.aspx?id=34595) 上下载了 *Windows6.1-KB2506143-x64.msu* 文件,安装了 PS3.0 。 安装完成后可以通过 `$PSVersionTable` 命令查看其版本。执行结果中 *PSVersion* 对应的值就是 *PowerShell* 的版本。 之后再次执行 *Add-Migration* 命令,显示了如下错误: > No database provider has been configured for this `DbContext`. A provider can be configured by overriding the *DbContext.OnConfiguring* method or by using *AddDbContext* on the application service provider. If *AddDbContext* is used, then also ensure that your `DbContext` type accepts a `DbContextOptions<TContext>` object in its constructor and passes it to the base constructor for `DbContext`. 看错误信息是因为没有提供 *provider* 或者没有提供一个接受 `DbContextOptions<TContext>` 对象的构造函数。 可以通过重写 *DbContext.OnConfiguring* 方法来指定 *provider*,也可以通过在 *Startup.ConfigureServices* 方法中调用 *AddDbContext* 来指定。 ```csharp public void ConfigureServices(IServiceCollection services) { // something else services.AddDbContext<MyDbContext>(optionsBuilder => optionsBuilder.UseSqlServer(Configuration.GetConnectionString("LocalDB"))); } ``` 这里通过 *Configuration.GetConnectionString* 方法获取 *appsettings.json* 配置文件中的数据库连接字符串。 由于使用的是 *SqlServer*,还需要安装 *Microsoft.EntityFrameworkCore.SqlServer* 包。 ```powershell Install-Package Microsoft.EntityFrameworkCore.SqlServer ``` 然后还需在自定义的 `DbContext` 中添加一个带 `DbContextOptions` 类型参数的构造函数,并传递给基类。 ```csharp public class MyDbContext : DbContext { // something else public MyDbContext(DbContextOptions options) : base(options) { } // something else } ``` 之后再次执行 *Add-Migration* 命令,执行成功会看到类似如下的结果: > Both Entity Framework Core and Entity Framework 6 are installed. The Entity Framework Core tools are running. Use 'EntityFramework\Add-Migration' for Entity Framework 6. > Build started... > Build succeeded. > To undo this action, use **Remove-Migration**. 此时会在项目的 *Migrations* 目录下生成一个 *20200419045958_InitialCreate.cs* 文件。 代码包含连个方法 *Up* 和 *Down*。*Up* 会在更新数据库时调用,*Down* 则是在回退时调用。 ```csharp public partial class InitialCreate : Migration { protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( name: "Activities", columns: table => new { ActFlag = table.Column<Guid>(nullable: false), Period = table.Column<TimeSpan>(nullable: false) }, constraints: table => { table.PrimaryKey("PK_Activities", x => x.ActFlag); }); migrationBuilder.CreateTable( name: "Cars", columns: table => new { CarId = table.Column<int>(nullable: false) .Annotation("SqlServer:Identity", "1, 1"), Color = table.Column<string>(nullable: true) }, constraints: table => { table.PrimaryKey("PK_Cars", x => x.CarId); }); migrationBuilder.CreateTable( name: "Employees", columns: table => new { EmpIdentity = table.Column<int>(nullable: false) .Annotation("SqlServer:Identity", "1, 1"), EmpAge = table.Column<int>(nullable: false), EmpName = table.Column<int>(nullable: false) }, constraints: table => { table.PrimaryKey("PK_Employees", x => x.EmpIdentity); }); } protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( name: "Activities"); migrationBuilder.DropTable( name: "Cars"); migrationBuilder.DropTable( name: "Employees"); } } ``` 如果再次执行,即使没有做任何修改,也还是会生成一个迁移代码文件,只不过 *Up* 和 *Down* 方法体是空的。 ```powershell Add-Migration EditNothing ``` ```csharp public partial class EditNothing : Migration { protected override void Up(MigrationBuilder migrationBuilder) { } protected override void Down(MigrationBuilder migrationBuilder) { } } ``` ### Remove-Migration *Add-Migration* 的执行结果中提到了 *Remove-Migration* 命令,这个命令用来删除生成的迁移代码。 为了防止误删除,*Remove-Migration* 命令只能每次删除一个迁移版本,而且不能指定版本名称,只能删除最近的一个迁移版本。 ```powershell Remove-Migration [-Force] [-Context <String>] [-Project <String>] [-StartupProject <String>] [<CommonParameters>] ``` 成功执行的话会显示类似如下的信息: > Build started... > Build succeeded. > Removing migration '20200419052626_InitialCreate'. > Removing model snapshot. > Done. 若迁移版本已经更新到数据库,删除时会显示类似如下的错误: > The migration '20200419052626_InitialCreate' has already been applied to the database. Revert it and try again. If the migration has been applied to other databases, consider reverting its changes using a new migration. 此时需要添加 *-Force* 参数,指定删除的同时回滚数据库的修改。 ```powershell Remove-Migration -Force ``` ### Update-Database 若要应用迁移到数据库,可以使用 *Update-Database* 命令。它提供了一个 *-Migration* 可选参数用于指定要应用到数据库的迁移版本,未指定时默认应用所有的迁移版本。 ```powershell Update-Database [[-Migration] <String>] [-Context <String>] [-Project <String>] [-StartupProject <String>] [<CommonParameters>] ``` 若找不到服务器,则会显示如下错误信息: > A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified) 执行成功会显示如下信息: > Build started... > Build succeeded. > Done. ## EFCore 提供的其它命令 除了上面讲到的三个名另外,从之前的帮助文档中可以看到 EFCore 还提供了另外几个命令: ### Drop-Database 删除数据库。 语法: ```powershell Drop-Database [-Context <String>] [-Project <String>] [-StartupProject <String>] [-WhatIf] [-Confirm] [<CommonParameters>] ``` ### Get-DbContext 获取 DbContext 类型信息。 语法: ```powershell Get-DbContext [-Context <String>] [-Project <String>] [-StartupProject <String>] [<CommonParameters>] ``` 示例: ```powershell Get-DbContext -Context "MyDbContext" ``` 执行结果: ```powershell Build started... Build succeeded. providerName databaseName dataSource options ------------ ------------ ---------- ------- Microsoft.EntityFrameworkCore.SqlServer SampleDb EDG2GYKVF8G5P6Z None ``` ### Scaffold-DbContext 从数据库构建 `DbContext` 和实体。 语法: ```powershell Scaffold-DbContext [-Connection] <String> [-Provider] <String> [-OutputDir <String>] [-ContextDir <String>] [-Context <String>] [-Schemas <String[]>] [-Tables <String[]>] [-DataAnnotations] [-UseDatabaseNames] [-Force] [-Project <String>] [-StartupProject <String>] [<CommonParameters>] ``` 示例可以参考[之前的一篇博客][1]。 ### Script-DbContext 从一个 `DbContext` 生成 SQL 脚本。 语法: ```powershell Script-DbContext [-Output <String>] [-Context <String>] [-Project <String>] [-StartupProject <String>] [<CommonParameters>] ``` 示例: ```csharp Script-DbContext -Output "MyDb.sql" -Context "MyDbContext" ``` 成功运行后会在解决方案的根目录生成一个 *MyDb.sql* 文件,内容如下: ```sql CREATE TABLE [Activities] ( [ActFlag] uniqueidentifier NOT NULL, [Period] time NOT NULL, CONSTRAINT [PK_Activities] PRIMARY KEY ([ActFlag]) ); GO CREATE TABLE [Cars] ( [CarId] int NOT NULL IDENTITY, [Color] nvarchar(max) NULL, CONSTRAINT [PK_Cars] PRIMARY KEY ([CarId]) ); GO CREATE TABLE [Employees] ( [EmpIdentity] int NOT NULL IDENTITY, [EmpAge] int NOT NULL, [EmpName] int NOT NULL, CONSTRAINT [PK_Employees] PRIMARY KEY ([EmpIdentity]) ); GO ``` ### Script-Migration 生成两个版本之前改动的 SQL 脚本。 语法: ```powershell Script-Migration [-From] <String> [-To] <String> [-Idempotent] [-Output <String>] [-Context <String>] [-Project <String>] [-StartupProject <String>] [<CommonParameters>] ``` ```powershell Script-Migration [[-From] <String>] [-Idempotent] [-Output <String>] [-Context <String>] [-Project <String>] [-StartupProject <String>] [<CommonParameters>] ``` 示例: ```powershell Script-Migration InitialCreate AddCarNumber -Context "MyDbContext" ``` 上面命令中的 *InitialCreate* 和 *AddCarNumber* 均为迁移的版本名称。 运行成功会生成类似如下的脚本,其中还包含了为了测试所生成的一个没有任何变更的迁移版本。 ```sql INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'20200419080544_EditNothing', N'3.1.3'); GO ALTER TABLE [Cars] ADD [Number] nvarchar(max) NULL; GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'20200419084331_AddCarNumber', N'3.1.3'); GO ``` [1]: /2018/5/29/%E3%80%90-net-core%E3%80%91entity-framework-core (【.NET Core】Entity Framework Core) [2]: https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/?tabs=vs (Migrations) --- > 购买本书 => [《.NET Core实战:手把手教你掌握380个精彩案例》][10] -- *周家安* 著 --- [10]:https://union-click.jd.com/jdc?e=&p=AyIGZRhaEwAQBFUZXBIyEgRSEl0QCxc3EUQDS10iXhBeGlcJDBkNXg9JHU4YDk5ER1xOGRNLGEEcVV8BXURFUFdfC0RVU1JRUy1OVxUBFQ5THlIQMm1AEkRdb11GZyNTK0BBZwYIbylWcHILWStaJQITBlYbXB0LFQJlK1sSMkBpja3tzaejG4Gx1MCKhTdUK1sRCxQBVxtTEQIQBlwrXBULIloNXwZBXUReEStrJQEiN2UbaxYyUGlUG1kUBhcGUBILQgUXDlMeUkBVRlUBS10XBkIABhkJRzIQBlQfUg%3D%3D (《.NET Core实战:手把手教你掌握380个精彩案例》)
版权声明:原创文章,未经允许不得转载。
https://www.liujiajia.me/2020/4/19/dotnet-core-efcore-migration
“Buy me a nongfu spring”
« [Jenkins] 在 Pipeline 中发送自定义钉钉消息(Windows环境)
《重构》 1. 重构,第一个示例 »
昵称
*
电子邮箱
*
回复内容
*
(回复审核后才会显示)
提交
目录
AUTHOR
刘佳佳
江苏 - 苏州
软件工程师