Entity Framework Code First (八)迁移 Migrations

转载:http://www.cnblogs.com/panchunting/p/entity-framework-code-first-migrations.html

创建初始模型和数据库

  在开始使用迁移(Migrations)之前,我们需要一个 Project 和一个 Code First Model, 对于本文将使用典型的 Blog 和 Post 模型

  • 创建一个新的控制台应用程序 MigrationsDemo;
  • 添加最新的 EntityFramework 到项目
    • Tools –> Library Package Manager –> Package Manager Console;
    • 运行命令 Install-Package EntityFramework  
  •   创建 Blog.cs 和 DbContext 的派生类 BlogContext.cs
public class Blog
{
    public int BlogId { get; set; }
    public string Name { get; set; }
}
public class BlogContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
}

  更改 Program.cs 以调用

Entity Framework Code First (八)迁移 Migrations
static void Main(string[] args)
{
    using (var db = new BlogContext())
    {
        db.Blogs.Add(new Blog { Name = "Another Blog" });
        db.SaveChanges();

        foreach (var blog in db.Blogs)
        {
            Console.WriteLine(blog.Name);
        }
    }

    Console.WriteLine("Press any key to exit...");
    Console.ReadKey();
}
Entity Framework Code First (八)迁移 Migrations

  运行查看结果

Entity Framework Code First (八)迁移 Migrations

  发现如上错误"CREATE DATABSE permission denied in databse 'master'"

  我们在 BlogContext 上的无参构造函数上添加诊断代码并设置调试断点

System.Diagnostics.Debug.Write(Database.Connection.ConnectionString);

  再次运行

Entity Framework Code First (八)迁移 Migrations

  我们注意到 Data Scource 竟然是 .\\SQLEXPRESS 而不是我们想要的 localDB , 这是因为:

  • 如果我们安装了 SQL Express,那么 database 将会安装在 local SQL Express instance,否则 Code First 才将尝试使用 localDB;
  • SQL Express 总是具有优先权,只要安装了它

  知道了原因我们就好解决了:

  • 如果想继续使用 SQL Express,那么就配置相应地权限,请参考 http://odetocode.com/Blogs/scott/archive/2012/08/14/a-troubleshooting-guide-for-entity-framework-connections-amp-migrations.aspx;
  • 如果想改用 localDB, 只需在.config 配置即可(放在 configSections 节点后面)
  <connectionStrings>
    <add name="BlogContext" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=BlogContext;Integrated Security=SSPI;" providerName="System.Data.SqlClient"/>
  </connectionStrings>

  再次运行就行了,让我们看一下后台生成的数据库

Entity Framework Code First (八)迁移 Migrations

 

启用迁移

  我们对模型 Blog 做一些更改:增加一个 Url 属性 

public string Url { get; set; }

  我们此时再次运行程序,发现如下错误

Entity Framework Code First (八)迁移 Migrations

  'InvalidOperationException' was unhandled. The model backing the 'BlogContext' context has changed since the database was created. Consider using Code First Migrations to update the database ( http://go.microsoft.com/fwlink/?LinkId=238269)

  正如错误消息提示的那样,是时候使用 Code First Migrations,第一步是运行如下的命令:

  • 在 Package Manager Console 下运行命令 Enable-Migrations

Entity Framework Code First (八)迁移 Migrations

 

Entity Framework Code First (八)迁移 Migrations

  这个命令将在项目下创建文件夹 Migrations 

  • The Configuration class 这个类允许你去配置如何迁移,对于本文将使用默认的配置(在本文中因为只有一个 ContextEnable-Migrations 将自动对 context type 作出适配);
  • An InitialCreate migration (本文为 201312240822431_InitialCreate.cs)这个迁移之所以存在是因为我们之前用 Code First 创建了数据库, 在启用迁移前,scaffolded migration里的代码表示在数据库中已经创建的对象,本文中即为表 Blog (列 BlogId 和 Name). 文件名包含一个 timestamp 以便排序(如果之前数据库没有被创建,那么 InitialCreate migration 将不会被创建,相反,当我们第一次调用 Add-Migration 的时候所有表都将归集到一个新的 migration 中)

 

多个实体锁定同一数据库

  当使用 EF6 之前的版本时,只会有一个 Code First Model 被用来生成/管理数据库的 Schema, 这将导致每个数据库只会有一张 __MigrationsHistory 表,从而无法辨别实体与模型的对应关系。

   从 EF6 开始,Configuration 类将会包含一个 ContextKey 属性,它将作为每一个 Code First Model 的唯一标识符, __MigrationsHistory 表中一个相应地的列允许来自多个模型(multiple models)的实体共享表(entries),默认情况下这个属性被设置成 context 的完全限定名。

 

生成、运行迁移

  Code First Migrations 有两个你需要熟悉的命令:

  •  Add-Migration 将 scaffold 创建下一次基于上一次迁移以来的更改的迁移;
  • Update-Databse 将任何挂起的迁移应用到数据库

  我们需要脚手架(scaffold 直译)一个迁移,以上面的 Url 属性为例,命令 Add-Migration 允许我们对迁移命名,我们姑且称之为 AddBlogUrl 

  • 在 Package Manager Console 中运行命令 Add-Migration AddBlogUrl;
  • 一个新的迁移(名称包含 timestamp 前缀)在目录 Migrations 中创建成功

Entity Framework Code First (八)迁移 Migrations

 

Entity Framework Code First (八)迁移 Migrations

Entity Framework Code First (八)迁移 Migrations
namespace MigrationsDemo.Migrations
{
    using System;
    using System.Data.Entity.Migrations;
    
    public partial class AddBlogUrl : DbMigration
    {
        public override void Up()
        {
            AddColumn("dbo.Blogs", "Url", c => c.String());
        }
        
        public override void Down()
        {
            DropColumn("dbo.Blogs", "Url");
        }
    }
}
Entity Framework Code First (八)迁移 Migrations

  我们现在可以对这个迁移进行编辑或者增加,但似乎看起来还不错,那我们就直接用 Update-Database 来应用到数据库吧

  • 在 Package Manager Console 中运行命令 Update-Database ;
  • AddBlogUrl 迁移将会被应用到数据库(表 Blogs 增加一列 Url

Entity Framework Code First (八)迁移 Migrations

 

Entity Framework Code First (八)迁移 Migrations

 

定制化迁移

  到目前为止我们生成并运行了一个迁移,但是没有对迁移做任何更改,下面我们将尝试做一些更改:在类 Bolg 上增加一属性 Rating

public int Rating { get; set; }

  新建 Post

Entity Framework Code First (八)迁移 Migrations
public class Post
{
    public int PostId { get; set; }
    [MaxLength(200)]
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}
Entity Framework Code First (八)迁移 Migrations

  在 Blog 中添加 Post 的集合

public virtual ICollection<Post> Posts { get; set; }

  在 Package Manager Console 中运行命令 Add-Migration AddPostClass

  生成的迁移如下

Entity Framework Code First (八)迁移 Migrations
Entity Framework Code First (八)迁移 Migrations
namespace MigrationsDemo.Migrations
{
    using System;
    using System.Data.Entity.Migrations;
    
    public partial class AddPostClass : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.Posts",
                c => new
                    {
                        PostId = c.Int(nullable: false, identity: true),
                        Title = c.String(maxLength: 200),
                        Content = c.String(),
                        BlogId = c.Int(nullable: false),
                    })
                .PrimaryKey(t => t.PostId)
                .ForeignKey("dbo.Blogs", t => t.BlogId, cascadeDelete: true)
                .Index(t => t.BlogId);
            
            AddColumn("dbo.Blogs", "Rating", c => c.Int(nullable: false));
        }
        
        public override void Down()
        {
            DropForeignKey("dbo.Posts", "BlogId", "dbo.Blogs");
            DropIndex("dbo.Posts", new[] { "BlogId" });
            DropColumn("dbo.Blogs", "Rating");
            DropTable("dbo.Posts");
        }
    }
}
Entity Framework Code First (八)迁移 Migrations

  接下来我们对迁移做些更改:

  • 在 Posts.Title 列上增加唯一索引;
  • 使 Blogs.Rating 列非空,对于表中已经存在的数据,新列都会被赋值成 CLR 的默认数据类型(如 Rating 是整型,故默认值为0),但是我们想指定默认值为3,这样存在的记录将会有一个合理的评分。

  更改后的代码如下

Entity Framework Code First (八)迁移 Migrations
namespace MigrationsDemo.Migrations
{
    using System;
    using System.Data.Entity.Migrations;
    
    public partial class AddPostClass : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.Posts",
                c => new
                    {
                        PostId = c.Int(nullable: false, identity: true),
                        Title = c.String(maxLength: 200),
                        Content = c.String(),
                        BlogId = c.Int(nullable: false),
                    })
                .PrimaryKey(t => t.PostId)
                .ForeignKey("dbo.Blogs", t => t.BlogId, cascadeDelete: true)
                .Index(t => t.BlogId)
                .Index(p => p.Title, unique: true);

            AddColumn("dbo.Blogs", "Rating", c => c.Int(nullable: false, defaultValue: 3));
        }
        
        public override void Down()
        {
            DropIndex("dbo.Posts", new[] { "Title" });
            DropForeignKey("dbo.Posts", "BlogId", "dbo.Blogs");
            DropIndex("dbo.Posts", new[] { "BlogId" });
            DropColumn("dbo.Blogs", "Rating");
            DropTable("dbo.Posts");
        }
    }
}
Entity Framework Code First (八)迁移 Migrations

  在 Package Manager Console 中运行命令 Update-Database –Verbose

Entity Framework Code First (八)迁移 Migrations

Entity Framework Code First (八)迁移 Migrations

 

数据移动 / 定制SQL 

  迄今为止,迁移都没有更改或移动数据,现在让我们看一下需要移动数据的例子。虽然没有对数据移动的原生支持,但是我们可以随意运行 SQL 脚本。

  让我们在 Post 中增加一个属性 Abstract, 稍后我们使用列 Content 的开头来填充此列(数据库已有记录) 

public string Abstract { get; set; }
  • 在 Package Manager Console 中运行命令 Add-Migration AddPostAbstract ;
  • 生成的迁移非常好,但是我们想使用 Content 的前 100 个字符来预填充 Abstract 列,我们可对迁移做如下更改
Entity Framework Code First (八)迁移 Migrations
namespace MigrationsDemo.Migrations
{
    using System;
    using System.Data.Entity.Migrations;
    
    public partial class AddPostAbstract : DbMigration
    {
        public override void Up()
        {
            AddColumn("dbo.Posts", "Abstract", c => c.String());
            Sql("UPDATE dbo.Posts SET Abstract = LEFT(Content, 100) WHERE Abstract IS NULL");
        }
        
        public override void Down()
        {
            DropColumn("dbo.Posts", "Abstract");
        }
    }
}
Entity Framework Code First (八)迁移 Migrations

  在 Package Manager Console 中运行命令 Update-Database –Verbose

 

迁移至指定版本(包括后退)

  迄今为止,我们总是升级至最新迁移,然而某些时候我们需要升级/降级至指定版本,例如我们想迁移数据库至运行 AddBlogUrl 迁移之后的状态,此时我们就可以使用 –TargetMigration来降级到这个版本

  在 Package Manager Console 中运行命令 Update-Database –TargetMigration: AddBlogUrl 

Entity Framework Code First (八)迁移 Migrations

  这个命令将会运行 AddBlogAbstract and AddPostClass 的 Down 命令

  如果你想回滚一切至空数据库,可以使用命令 Update-Database –TargetMigration: $InitialDatabase

 Entity Framework Code First (八)迁移 Migrations

 

得到SQL脚本

  如果其它开发人员也希望在他们自己的机器上拥有这些更改,他们只需在我们 check in 代码至 source control 的时候做一次同步即可,一旦他们拥有了这些迁移,只需运行命令 Update-Database 就可以把这些更改应用于本地。但是如果我们想把这些更改推送至测试服务器或生产服务器,我们也许需要一份 SQL 脚本提供给 DBA

  • 在运行 Update-Database 的时候指定 -Specify 标记,我们就能够使得这些更改被写入一个脚本中而不是被应用,我们同时也会为此脚本指定源迁移和目标迁移,例如我们希望产生的脚本是从一个空数据库($InitialDatabase)到最新的版本(AddPostAbstract 迁移);(注意:如果你没有指定目标迁移,那么迁移将始终更新至最新版本;如果你没有指定源迁移,那么迁移将以数据库目前状态为初始)
  • 在 Package Manager Console 中运行命令 Update-Database -Script -SourceMigration: $InitialDatabase -TargetMigration: AddPostAbstract

Entity Framework Code First (八)迁移 Migrations

  产生的 SQL 脚本如下

Entity Framework Code First (八)迁移 Migrations
Entity Framework Code First (八)迁移 Migrations
DECLARE @CurrentMigration [nvarchar](max)

IF object_id('[dbo].[__MigrationHistory]') IS NOT NULL
    SELECT @CurrentMigration =
        (SELECT TOP (1) 
        [Project1].[MigrationId] AS [MigrationId]
        FROM ( SELECT 
        [Extent1].[MigrationId] AS [MigrationId]
        FROM [dbo].[__MigrationHistory] AS [Extent1]
        WHERE [Extent1].[ContextKey] = N'MigrationsDemo.BlogContext'
        )  AS [Project1]
        ORDER BY [Project1].[MigrationId] DESC)

IF @CurrentMigration IS NULL
    SET @CurrentMigration = '0'

IF @CurrentMigration < '201312240822431_InitialCreate'
BEGIN
    CREATE TABLE [dbo].[Blogs] (
        [BlogId] [int] NOT NULL IDENTITY,
        [Name] [nvarchar](max),
        CONSTRAINT [PK_dbo.Blogs] PRIMARY KEY ([BlogId])
    )
    CREATE TABLE [dbo].[__MigrationHistory] (
        [MigrationId] [nvarchar](150) NOT NULL,
        [ContextKey] [nvarchar](300) NOT NULL,
        [Model] [varbinary](max) NOT NULL,
        [ProductVersion] [nvarchar](32) NOT NULL,
        CONSTRAINT [PK_dbo.__MigrationHistory] PRIMARY KEY ([MigrationId], [ContextKey])
    )
    INSERT [dbo].[__MigrationHistory]([MigrationId], [ContextKey], [Model], [ProductVersion])
    VALUES (N'201312240822431_InitialCreate', N'MigrationsDemo.BlogContext',  0x1F8B0800000000000400CD574B4FDB4010BE57EA7FB0F6D41EC826E1D22207040954511B4018B86FEC4958751FAE778D92DFD6437F52FF4267FD8E4D1E200EBD44F178E69B996FE7B1FEFBFB8F7FB692C27B86C470AD4664D0EB130F54A823AE962392DAC5D1177276FAF1837F19C995F758EA1D3B3DB45466449EAC8D4F2835E11348667A928789367A617BA19694459A0EFBFDAF7430A0801004B13CCFBF4B95E512B2077C1C6B15426C5326663A02610A39BE093254EF9A4930310B6144667C99308B519809484DBC73C11946118058108F29A56DF6F6E4C1406013AD96418C0226EED731A0DE82090345EC27B5FAA169F4872E0D5A1BBE8906522588295E221576EDC2CBD21C910BA1974D0DD4F90EEB0D018A6E131D4362D777B068D84D23E2D14D5BDA36AE4C5B762E8411992A7B3C24DE752A049B0BA8186B501B589DC03750800701D12DB3161264701A41964A2782963FF75B7AC323C24A23DE8CAD7E805ADA273C60B622DE155F41544A8A081E14C7C244239BA4B0CFC94322DED9874FEB93EA9E1F96B0651C296990EA64B0B2ADB3CCF503B00D4D43BC1A3C2FE65E56062F4650F9AAFB84E68D523614DDD251FE8CC53192D1E8B042E205797B8D8F82D797B4CC3168685EA8EC2ADACA13960F5B42EB2DBAC648AF7862EC84593667EE38C691ECA81DC06CE9A94970BB7F6ABE4B6DF73FB7D89C31BD6E433699BBC26424567E96175431BCD4C785611032C1922D5D38D622956A5747EF42C97BAB89914B0E47C81AA7099009BAF63E6DE5DF269876186ECDA5F671EDAAF4B64AE5BDAAF85665FB4595ED5F289DB2CB558887C43CF3C8955CB0361664CF29F4825F622C38E65B2BCC98E20B30F65EFF049C83C3FE60D8DA4B6FD811D49848FCCF8B823B0AF6AE82CE1E397C37A86796844F2CF924D9EA7313E995F3FF1538AF9BF1DD81B57FD26F1DF479D58D4834C74BCD7D1E60B11ADEB803BA1DE0D3E6C5CB9F80E1CB1AC25DC314846EEED5A0A5CE542D74493166D48CA854699DC00C2C8B9098F3C4F2050B2DBE0EC1986C153F3291A2CAA59C43345537A98D537B6E0CC8B9D8B83EF874B7FF6CD16DC6ECDFC4D9E47E8F14304C8E29C08DBA48B988AAB8AFBAA5BC0DC2D548D11F18155E45106EB9AE90AEB53A10A8A06F023128D75DF720638160E64605EC19B6C7B69FC34DC6FC0967B8FEA429306A7BF71D40DD87C0E93F1D45E2A93A0C0000 , N'6.0.2-21211')
END

IF @CurrentMigration < '201312310618077_AddBlogUrl'
BEGIN
    ALTER TABLE [dbo].[Blogs] ADD [Url] [nvarchar](max)
    INSERT [dbo].[__MigrationHistory]([MigrationId], [ContextKey], [Model], [ProductVersion])
    VALUES (N'201312310618077_AddBlogUrl', N'MigrationsDemo.BlogContext',  0x1F8B0800000000000400CD574B4FDB4010BE57EA7FB0F6D41EC826E1D22207040954511B4018B86FEC4958751FAE778D92DFD6437F52FF4267FD8E4D1E200EBD44F178E69B996FE7B1FEFBFB8F7FB692C27B86C470AD4664D0EB130F54A823AE962392DAC5D1177276FAF1837F19C995F758EA1D3B3DB45466449EAC8D4F2835E11348667A928789367A617BA19694459A0EFBFDAF7430A0801004B13CCFBF4B95E512B2077C1C6B15426C5326663A02610A39BE093254EF9A4930310B6144667C99308B519809484DBC73C11946118058108F29A56DF6F6E4C1406013AD96418C0226EED731A0DE82090345EC27B5FAA169F4872E0D5A1BBE8906522588295E221576EDC2CBD21C910BA1974D0DD4F90EEB0D018A6E131D4362D777B068D84D23E2D14D5BDA36AE4C5B762E8411992A7B3C24DE752A049B0BA8186B501B589DC03750800701D12DB3161264701A41964A2782963FF75B7AC323C24A23DE8CAD7E805ADA273C60B622DE155F41544A8A081E14C7C244239BA4B0CFC94322DED9874FEB93EA9E1F96B0651C296990EA64B0B2ADB3CCF503B00D4D43BC1A3C2FE65E56062F4650F9AAFB84E68D523614DDD251FE8CC53192D1E8B042E205797B8D8F82D797B4CC3168685EA8EC2ADACA13960F5B42EB2DBAC648AF7862EC84593667EE38C691ECA81DC06CE9A94970BB7F6ABE4B6DF73FB7D89C31BD6E433699BBC26424567E96175431BCD4C785611032C1922D5D38D622956A5747EF42C97BAB89914B0E47C81AA7099009BAF63E6DE5DF269876186ECDA5F671EDAAF4B64AE5BDAAF85665FB4595ED5F289DB2CB558887C43CF3C8955CB0361664CF29F4825F622C38E65B2BCC98E20B30F65EFF049C83C3FE60D8DA4B6FD811D49848FCCF8B823B0AF6AE82CE1E397C37A86796844F2CF924D9EA7313E995F3FF1538AF9BF1DD81B57FD26F1DF479D58D4834C74BCD7D1E60B11ADEB803BA1DE0D3E6C5CB9F80E1CB1AC25DC314846EEED5A0A5CE542D74493166D48CA854699DC00C2C8B9098F3C4F2050B2DBE0EC1986C153F3291A2CAA59C43345537A98D537B6E0CC8B9D8B83EF874B7FF6CD16DC6ECDFC4D9E47E8F14304C8E29C08DBA48B988AAB8AFBAA5BC0DC2D548D11F18155E45106EB9AE90AEB53A10A8A06F023128D75DF720638160E64605EC19B6C7B69FC34DC6FC0967B8FEA429306A7BF71D40DD87C0E93F1D45E2A93A0C0000 , N'6.0.2-21211')
END

IF @CurrentMigration < '201312310648099_AddPostClass'
BEGIN
    CREATE TABLE [dbo].[Posts] (
        [PostId] [int] NOT NULL IDENTITY,
        [Title] [nvarchar](200),
        [Content] [nvarchar](max),
        [BlogId] [int] NOT NULL,
        CONSTRAINT [PK_dbo.Posts] PRIMARY KEY ([PostId])
    )
    CREATE INDEX [IX_BlogId] ON [dbo].[Posts]([BlogId])
    CREATE UNIQUE INDEX [IX_Title] ON [dbo].[Posts]([Title])
    ALTER TABLE [dbo].[Blogs] ADD [Rating] [int] NOT NULL DEFAULT 3
    ALTER TABLE [dbo].[Posts] ADD CONSTRAINT [FK_dbo.Posts_dbo.Blogs_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [dbo].[Blogs] ([BlogId]) ON DELETE CASCADE
    INSERT [dbo].[__MigrationHistory]([MigrationId], [ContextKey], [Model], [ProductVersion])
    VALUES (N'201312310648099_AddPostClass', N'MigrationsDemo.BlogContext',  0x1F8B0800000000000400D558CD6EE33610BE17E83B083AB505D64AB29736B07791759222681D0751B2D78091C60E518A54452AB09F6D0F7DA4BE4287FA33454AB6ECAC17DD4B1093331F6786DF0C67F4EF977FC61F5709F35E219354F0897F3A3AF13DE09188295F4EFC5C2DDEFDEA7FFCF0E30FE3AB3859799F6BB9F75A0E35B99CF82F4AA5E74120A31748881C2534CA84140B358A4412905804672727BF05A7A70120848F589E37BECFB9A209143FF0E754F0085295133613313059ADE34E58A07AB7240199920826FE8C2E33A2D00A790989F0BD0B46095A11025BF81EE15CA862F7FC5142A832C197618A0B843DAC5340B90561122ADBCF37E243DD3839D36E041BC583C2E0370EA28B57180AB5D6E6156E4EFC4F4C2C4D0994F903D6AD055CBACB440A995ADFC3C2D0BB897D2F68EB06B672A36AE9691326FE0D57EFCF7CEF36678C3C336822668436542283DF81035E04C4774429C83082373114AE381658E7E9BFF5697845C834DF9B91D59FC097EA052F98AC7CEF9AAE20AE572A0B1E394562A292CA72D875C863C68E7EC63D8643036F0F9C85714B5EE9B288A3857627A492BE770FACA4F70B4D4B5A8FF4CE53C10AEF3A13C9BD609578B1F8F440B225283443D83BA1C8B3C832611C6C08B795861AE6101A6ABD436858EB7D2B1A3E50C5B6F110F3F52B70044B9B427B8ECEC561493C948B25D9F6A7624D38978A35498750F1424A11D1E268831B4F1D75F18AC75EAF0D65C06BAB31E63953346534C22327FE2F4E34BAC09ADCDA8095DEB7C14E7D3B2FE6FC121828F02EA2F27D99121991D8BD038C41DC5EC154824C739830648F5419A15CB97947794453C2FA4CB614F67831B4510DBCBD730929709D617D717FDBB90DBC15A45D3119070669DCB2A6B3103520330C2832736597B8523E0465486255DE10B5C50287416DE5AAA43BCA251F2D65C3813642956FC6BE938C761CB7E5456364639F730DDB32C150AF626313BAED4847BE37B7B1E9F382B2D1AB1BC2A0A7231CCF489A6201353AC46AC50BCBF670FA2EDCBF254B4A8C20921D9D59636D7312BE3B6409D6AE2EF5315CD34CAA4BA2C833D1F5761A278ED800EED527991474EFA826552DADFF2F35DA3DF2A88B229BC85DA333894EE8E23DB5AED7552B9A72C248D6F3004D05CB13BE3DCFFB51CADED0C428578623148D9F09502C0CD7AF9B3A13A25E7351C6811545A7A239F7E494FFF6A50FA24499B86FA084DBDC0DA244B75A5F28EB8ECE0C657777B80DA5EAD34C906A693846D3859928CDE2709CFD487E547238C5D416694E6F8AAA553CC75521DB3D733B95AD14F13D0CCF2B8D75550BD7524132D202A3F06F3665B4086D2D30239C2E40AA07F11770DD5B9F9E59A3FB0163742065CCFECFB334D521D839A6ECEAD2B78CCFFC9564D10BC97E4AC8EA671369CF11F94D38ED31B8F079AB4BDFC9047A94CB6B0D9D75D4DDB173BF0BB066CC375D6607810FBACC4366B8B2CFFD96A356BBD13D60663C6856EBE9C78E369F7D1F3399DB3EEF9ECC7A07B3F2819AF8F1B3C05B2DD9DB3DAE74CD6CBD235B176CE71075A469CEF479D3A3EF1AE09C99EF38339BDB4E20478C0FFDC84D49971B08FDD99F43D462472373C317A226A965512D6255AE19281223752E3245172452B81D8194C5D3F499B01C45AE9267886FF83C5769AED065489E59EB3BA126FBB6F38BC1B46DF3789E166DF5D77001CDA4E802CCF9A79CB2B8B1FBBAA3EEF640E82CAADE2B7D974ABF5BCB7583742BF840A02A7C4DF23F4092320493731E9257E8B76D770CDB111B5F5282B349222B8C8D3EFE44FAC5C9EAC37FEC5F9589AA1A0000 , N'6.0.2-21211')
END

IF @CurrentMigration < '201312310729575_AddPostAbstract'
BEGIN
    ALTER TABLE [dbo].[Posts] ADD [Abstract] [nvarchar](max)
    UPDATE dbo.Posts SET Abstract = LEFT(Content, 100) WHERE Abstract IS NULL
    INSERT [dbo].[__MigrationHistory]([MigrationId], [ContextKey], [Model], [ProductVersion])
    VALUES (N'201312310729575_AddPostAbstract', N'MigrationsDemo.BlogContext',  0x1F8B0800000000000400D559CD6EE33610BE17E83B083AB505D64AB29736B077E1759222689D0451B2D78096C636518A54452AB09F6D0F7DA4BE4287FA1729D9B2B35E742F414CCE7C9C197E339CB1FFFDF2CFF8E32662CE2B24920A3E71CF4767AE033C1021E5AB899BAAE5BB5FDD8F1F7EFC617C1D461BE77329F75ECBA126971377AD547CE97932584344E428A24122A458AA5120228F84C2BB383BFBCD3B3FF700215CC4729CF163CA158D20FB801F67820710AB94B0B90881C9621D77FC0CD5B92311C898043071E77495108556C82B8884EB4C192568850F6CE93A8473A1B2DDCB6709BE4A045FF9312E10F6B48D01E5968449286CBFACC587BA7176A1DDF06AC5A3C2E0560EA28BD7180AB5D5E6656E4EDC4F4CAC9A1228F3076C5B0BB8F490881812B57D846543EF36741DAFADEB99CA95AAA1A74D98B8B75CBDBF709DBB9431B2605045AC115A5F89047E070E7811103E10A520C108DE8690B96259609CA7FF96A7E11521D35C674E367F025FA9355E30D9B8CE0DDD4058AE14163C738AC4442595A4B0EF90E7849DFC8C470C8706DE1D3803E38EBCD255164703ED4148255DE711584EEF358D735A8FF4CE4BC60AE72611D1A3608578B6F8F2449215283443983BBE4893C03061ECD584DB49430D730C0DB5DE31342CF5BE150D9FA862BB7888F9FA153882A54DA13D27E7E27421554282D31F34AC5A0C257DCEEAC3395F32DBE67C990D43383F955204343BBA41C2978E027CCD43A7D7863CE0A5D518F394291A331AE09113F7172B1A5D605512D760B9F76DB073D74CC07B7E050C1438D3207FC866440624B4EF006310B657306721D1C94218D254F38772652738E5018D09EB33D95038E069D24655F0E6CE15C4C0752AF7C5FD6DE756F04690F6C564EC354863D74F9DEEA80149C380AC046CCC5A9ACBFBA01A9258FE6BA2B6586031A8AD5CBC1D9672CE4743B9E1401BA1C8B7C6BE958C661C77E5456564659F750DBB32A1A15EC4C62474DB918E7CAF6EA36E28BDBCA32C3B4FAFA7F51CCF491C63016DB4A2C58AE3E77DE8EC9D7F78EF17E5185E203B5AC0CADAEA247CE0C80A8C5DFDA684704313A9AE88220BA2EBED2C8C2CB101DC2B4F6A52D0BEA39254A5B4FE3FD76837E3A32E8AD491BB4167229DD0D9C36D5CAFAD9675FF8491A4E7019A0996467C779EF7A3E44D6813235F198E9075984D806C61B87ED93D3621CA351B65EC1951B42A9A754F56F96F5FFA204AE489FB064AD85DE4204A74ABF585B26C1D9BA1EC6E4377A1140D6113A4581A8E51B57B4D946A71384EDDCE3581EAD5E14887A5CB496966956553A43ABD2ACF46191E172571FFD704568DCC455C07C3F34A435D1FFDAD54108DB4C0C8FF9BCD18CD2EA91498134E9720D593F80BB81E07CE2F8C6F1B8E98FC3D2943F67F1EFFA90EC1DEC96A5FBFBF63E2E7AF2409D624F929229B9F9B48074EF56FC2694FEE99CF3B5DFA4E86E6935C5E6B4E2EA36E4FCA875D803116BFE932CDD1F74D601DD97014338E192DF3F6FB5B4E80EDFEFB8851F6A811B2A74D3CD9D8F87D8C8A7657BF7F60EC9D17F3D76EE2860B81B79AB3B77B8AEA1A257B27C92ED8CED9EE444366D3E77A74D837575AA3E8694649BB37418E347EE8406E4ABAAA21F4CF1E1C82163B2A995BBE1425490D8B4A11A372CD419110A9334D145D6239C4ED00A4CCDEB9CF84A528721D2D20BCE5F7A98A53852E43B460ADEF4935D9779D9FCDCB6D9BC7F771D6ED7F0D17D04C8A2EC03DFF9452165676DF74D4DD1E089D45C5E3A7EF52E94770B5AD90EE041F085484AF4AFE2788628660F29EFBE415FA6DDB1FC376C4C65794E0C814C902A3D6C78F48BF30DA7CF80FF7E621BAAA1B0000 , N'6.0.2-21211')
END
Entity Framework Code First (八)迁移 Migrations

 

产生幂等脚本(EF6+)

  从 EF6 开始,如果你使用 –SourceMigration $InitialDatabase, 产生的脚本将是幂等的,幂等脚本意味着无论数据库当前处于什么版本/状态,都能升级至最新版本或指定版本(指定 TargetMigration),生成的脚本包括检查表 __MigrationsHistory 的逻辑以及只更新之前从未更新的

 

在应用程序启动时自动升级(MigrateDatabaseToLatestVersion初始化器)

  当你发布部署应用程序的时候,可能希望当程序启动的时候它自动更新数据库(更新应用任何未更新的迁移),你可以通过注册 MigrateDatabaseToLatestVersion 数据库初始化器来实现这一点,数据库初始化器只包含一些逻辑检查用于确保数据库被正确设置,这个逻辑检查将会在AppDomain 的 context 第一次被使用的时候执行。

  当我们创建一个初始化器的实例时,需要指定 context typeBlogContext)以及 migrations configuration Configuration)- 这个迁移配置类是在我们启用迁移时生成的 Migrations 目录下增加的

Entity Framework Code First (八)迁移 Migrations

Entity Framework Code First (八)迁移 Migrations
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MigrationsDemo.Migrations;

namespace MigrationsDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<BlogContext, Configuration>());

            using (var db = new BlogContext())
            {
                db.Blogs.Add(new Blog { Name = "Another Blog " });
                db.SaveChanges();

                foreach (var blog in db.Blogs)
                {
                    Console.WriteLine(blog.Name);
                }
            }

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }
    }
}
Entity Framework Code First (八)迁移 Migrations

原文:http://msdn.microsoft.com/en-us/data/jj591621