前言
緊接着前面一篇博文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); } }
調用結果展示
有兩條數據,一條是上一篇博文添加的數據,第二條就是今天測試添加的。