前言
緊接着前面一篇博文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);
}
}
調用結果展示

有兩條數據,一條是上一篇博文添加的數據,第二條就是今天測試添加的。
