Entity Framework CodeFirst数据迁移
前言
紧接着前面一篇博文Entity Framework CodeFirst尝试。
我们知道无论是“Database First”还是“Model First”当模型发生改变了都可以通过Visual Studio设计视图进行更新,那么对于Code First如何更新已有的模型呢?今天我们简单介绍一下Entity Framework的数据迁移功能。
Entity Framework配置
当我们对项目进行Entity Framework进行安装引用的时候,同时生成了两个配置文件
packages.config文件:
<?xml version= "1.0" encoding= "utf-8" ?> <packages> <package id= "EntityFramework" version= "5.0.0" targetFramework= "net45" /> </packages> |
App.config文件:
<?xml version= "1.0" encoding= "utf-8" ?> <configuration> <configSections> <!-- For more information on Entity Framework configuration, visit http: //go.microsoft.com/fwlink/?LinkID=237468 --> <section name= "entityFramework" type= "System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission= "false" /> </configSections> <startup> <supportedRuntime version= "v4.0" sku= ".NETFramework,Version=v4.5" /> </startup> <entityFramework> <defaultConnectionFactory type= "System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework" > <parameters> <parameter value= "v11.0" /> </parameters> </defaultConnectionFactory> </entityFramework> </configuration> |
packages.config内容比较简单,首先是EF自身版本,然后在安装过程中根据当前应用的.NET Framework版本配置了“targetFramework”,因为不同的.NET Framework版本对应的EF程序集不同,这在安装过程中会自动识别并配置。
App.config中自动添加了“entityFramework”配置节,在EF包安装过程中自动根据当前环境配置了“defaultConnectionFactory”, “defaultConnectionFactory”是EF默认的连接配置,只有在没有配置连接字符串时生效。
配置了数据库链接字符串的App.config配置文件
<?xml version= "1.0" encoding= "utf-8" ?> <configuration> <configSections> <!-- For more information on Entity Framework configuration, visit http: //go.microsoft.com/fwlink/?LinkID=237468 --> <section name= "entityFramework" type= "System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission= "false" /> </configSections> <connectionStrings> <add name= "CodeFirstTest" connectionString= "Data Source=.;Database=CodeFirstTest;UID=sa;PWD=sa123;" providerName= "System.Data.SqlClient" ></add> </connectionStrings> <startup> <supportedRuntime version= "v4.0" sku= ".NETFramework,Version=v4.5" /> </startup> <entityFramework> <defaultConnectionFactory type= "System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework" > <parameters> <parameter value= "v11.0" /> </parameters> </defaultConnectionFactory> </entityFramework> </configuration> |
CodeFirst 数据迁移
现在让我们在上一篇文章的Entity Framework CodeFirst尝试 的基础上给Order添加一个"Employee”属性,然后运行,不出意外的话你将看到如下异常:
从异常信息我们可以看出,EF已经检测到模型发生了改变,建议我们使用”Code First Migrations”对模型进行更新。
在开始Code First数据库迁移之前,我们先对上一节编写的OrderTestContext类进行修改添加默认构造函数,因为Code First Migrations将会使用数据库上下文的默认构造函数进行数据迁移操作(尽管没有默认构造函数所有的数据操作都能正常进行,但是对于数据迁移这是必须的),因此我们需要添加一个默认构造函数,并且该构造函数中必须传入我们的数据库连接名称,否则将会把更新应用到EF默认数据库上。下面是我们的OrderTestContext:
public class OrderTestContext:DbContext { public OrderTestContext(): base ( "CodeFirstTest" ) { } public OrderTestContext( string connectionName) : base (connectionName) { } public DbSet<Order> Orders { get ; set ;} public DbSet<OrderDetail> OrderDetails { get ; set ; } } |
下面我们将借助于”Code First Magrations” 进行模型更新。然后找到如下图所示的位置
1.在“程序包管理器控制台”键入命令:Enable-Migrations -ProjectName CodeFirstTest
如果多次执行此命令可以添加-Force参数
添加后,项目中添加了一个名为Migrations的文件夹
查看Configuration文件中的代码为:
namespace CodeFirstTest.Migrations { using System; using System.Data.Entity; using System.Data.Entity.Migrations; using System.Linq; internal sealed class Configuration : DbMigrationsConfiguration<CodeFirstTest.OrderTestContext> { public Configuration() { AutomaticMigrationsEnabled = false ; } protected override void Seed(CodeFirstTest.OrderTestContext context) { // This method will be called after migrating to the latest version. // You can use the DbSet<T>.AddOrUpdate() helper extension method // to avoid creating duplicate seed data. E.g. // // context.People.AddOrUpdate( // p => p.FullName, // new Person { FullName = "Andrew Peters" }, // new Person { FullName = "Brice Lambson" }, // new Person { FullName = "Rowan Miller" } // ); // } } } |
方法Seed中可以进行数据迁移后的数据初始化工作,将在每次迁移之后运行。如上代码所示,AddOrUpdate是IDbSet<TEntity>的扩展方法,如果指定条件的数据不存在,则会添加,如果存在,会更新。所以,如果数据是通过此方法来初始化的,在与业务更新之后,再次进行数据迁移后,还是会被还原。
还有一个名为InitialCreate的类,配置生成数据库的细节:
namespace CodeFirstTest.Migrations { using System; using System.Data.Entity.Migrations; public partial class InitialCreate : DbMigration { public override void Up() { CreateTable( "dbo.Orders" , c => new { ID = c.Int(nullable: false , identity: true ), Customer = c.String(), OrderDate = c.DateTime(nullable: false ), }) .PrimaryKey(t => t.ID); CreateTable( "dbo.OrderDetails" , c => new { ID = c.Int(nullable: false , identity: true ), Product = c.String(), OrderID = c.Int(nullable: false ), }) .PrimaryKey(t => t.ID) .ForeignKey( "dbo.Orders" , t => t.OrderID, cascadeDelete: true ) .Index(t => t.OrderID); } public override void Down() { DropIndex( "dbo.OrderDetails" , new [] { "OrderID" }); DropForeignKey( "dbo.OrderDetails" , "OrderID" , "dbo.Orders" ); DropTable( "dbo.OrderDetails" ); DropTable( "dbo.Orders" ); } } } |
3.执行“Add-Migration AddEmployee”命令,添加一个名为AddEmployee的迁移
4.执行“Update-Database”命令,更新数据库架构
如果更新数据库存在冲突而不能执行更新,可以添加 -Force强制执行,例如:“Update-Database -Force”
5.设置自动迁移
每次都通过控制台来进行迁移太过麻烦,可以设置为自动迁移。
1. AutomaticMigrationsEnabled:获取或设置 指示迁移数据库时是否可使用自动迁移的值。
2. AutomaticMigrationDataLossAllowed:获取或设置 指示是否可接受自动迁移期间的数据丢失的值。如果设置为false,则将在数据丢失可能作为自动迁移一部分出现时引发异常。
3.在Global.asax.cs中添加初始化策略
Database.SetInitializer(new MigrateDatabaseToLatestVersion<OrderTestContext, Configuration>());
代码调用实例
using ( var db = new OrderTestContext( "CodeFirstTest" )) { Order Order = new Order(); Order.Customer = "aehyok" ; Order.OrderDate = DateTime.Now; db.Orders.Add(Order); db.SaveChanges(); IQueryable<Order> Orders = from Orderes in db.Orders select Orderes; foreach (Order O in Orders) { Console.WriteLine( "OrderID is {0},Customer is {1}" , O.ID, O.Customer); } } |
调用结果展示
有两条数据,一条是上一篇博文添加的数据,第二条就是今天测试添加的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构