Entity Framework first code

时间:2024-03-31 19:54:19
  1. EF43 基于代码的迁移演练
  2. 准备工作
  3. 创建初始的模型和数据库
  4. 启用迁移
  5. 第一个迁移
  6. 定制迁移
  7. 数据操作定制 SQL
  8. 迁移到特定版本包含降级
  9. 获取迁移的脚本
 
 

EF4.3 基于代码的迁移演练

原文地址:http://blogs.msdn.com/b/adonet/archive/2012/02/09/ef-4-3-code-based-migrations-walkthrough.aspx

原文名称:EF 4.3 Code-Based Migrations Walkthrough

准备工作

在开始之前,我们需要一个项目,以及一个 Code First 的模型,对于这次演示,我们使用典型的博客 Blog 和回复 Post 模型。

1. 创建新的  MigrationsCodeDemo 控制台应用程序

Entity Framework first code

2. 为项目添加最新版本的 EntityFramework NuGet 包。

找到包管理器控制台。

Entity Framework first code

运行 Install-Package EntityFramework 命令。

Entity Framework first code

成功之后的项目文件如下:

Entity Framework first code

创建初始的模型和数据库

1. 增加如下的 Model.cs 文件,代码定义了一个单个的 Blog 类表示我们的模型对象,BlogContext 类就是 EF Code First 的上下文。

using
System.Data.Entity;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity.Infrastructure;

namespace MigrationsCodeDemo
{
    publicclass BlogContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }
    }

    publicclass Blog
    {
        publicint BlogId { get; set; }
        publicstring Name { get; set; }
    }
}
 

2. 现在我们已经有了一个模型,是时候进行一次数据访问了。使用如下的代码更新 Program.cs 文件。

using
System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MigrationsCodeDemo
{
    class Program
    {
        staticvoid 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);
                }
            }
        }
    }
}
3. 运行程序,现在就可以在你本地的 SQLExpress 数据库中看到数据库了。

Entity Framework first code

启用迁移

1. 在 Blog 类中增加一个 Url 属性。

    public class Blog
    {
        public int BlogId { get; set; }
        public string Name { get; set; }
        public string Url { get; set; }
    }

2. 现在运行程序,会看到如下的异常。
未经处理的异常:  System.InvalidOperationException: 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).

3. 正如异常建议,现在是开始使用 Code First 迁移的时候了,第一步是为我们的上下文启用迁移支持。

   在包管理器的控制台中执行命令:Enable-Migrations

Entity Framework first code

4. 这个命令在项目中增加名为 Migrations 文件夹,文件夹中包含两个文件。

Entity Framework first code

Configuration 类,这个类允许你配置你的上下文的迁移行为,在这个演示中,我们仅仅使用默认配置。

因为在这个项目中只有一个上下文,Enable-Migrations 自动填充应用的这个上下文。

201202171353373_InitialCreate.cs 中的 InitialCreate ,生成这个迁移是因为我们已经通过 Code First 创建了一个数据库。这个迁移中的代码表示我们已经创建的数据库,

 

namespace
MigrationsCodeDemo.Migrations
{
    using System.Data.Entity.Migrations;
    
    publicpartialclass InitialCreate : DbMigration
    {
        publicoverridevoid Up()
        {
            CreateTable(
                "Blogs",
                c => new
                    {
                        BlogId = c.Int(nullable: false, identity: true),
                        Name = c.String(),
                    })
                .PrimaryKey(t => t.BlogId);
            
        }
        
        publicoverridevoid Down()
        {
            DropTable("Blogs");
        }
    }
}
 

第一个迁移

你会使用到两个命令

Add-Migration,将会基于你对模型的修改创建一个迁移的脚手架。

Update-Database,将没有提交的修改提交到数据库。

1. 我们首先为我们新增加的 Url 属性创建一个迁移,Add-Migration 会帮我们完成这个工作,我们为这个迁移命名为:AddBlogUrl。

 执行:Add-Migration AddBlogUrl

Entity Framework first code

项目中增加了一个文件 201202171413369_AddBlogUrl.cs

 

Entity Framework first code

 

内容如下:

 

namespace
MigrationsCodeDemo.Migrations
{
    using System.Data.Entity.Migrations;
    
    publicpartialclass AddBlogUrl : DbMigration
    {
        publicoverridevoid Up()
        {
            AddColumn("Blogs", "Url", c => c.String());
        }
        
        publicoverridevoid Down()
        {
            DropColumn("Blogs", "Url");
        }
    }
}
 

3. 我们可以在这个迁移中编辑或者增加内容,但是现在看起来就很不错,让我们将这个迁移提交到数据库中。

执行: Update-Database

Entity Framework first code

4. 现在的数据库中已经包含了 Url 列。

Entity Framework first code

定制迁移

下面我们看看如何定制迁移。

1. 在代码中增加一个回复的类 Post,同时在 Blog 中增加一个评分属性。

using
System.Data.Entity;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity.Infrastructure;

namespace MigrationsCodeDemo
{
    publicclass Blog
    {
        publicint BlogId { get; set; }
        publicstring Name { get; set; }         
        publicstring Url { get; set; }
        public int Rating { get; set; }        public List<Post> Posts { get; set; }
    }

    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; }    }
}
 

2. 使用 Add-Migration 命令创建一个迁移,命名为 AddPostClass。

Entity Framework first code

3.  Code First Migrations 帮我们创建好了一个迁移,但是我们希望能增加如下的修改:

     首先,为 Posts.Title 增加一个唯一索引。

     增加一个非空的 Blogs.Rating 列,如果表中已经存在了数据,那么就将 CLR 默认的数据类型值赋予新增加的列 (Rating 是整数类型,应该就是 0), 但是,我们希望默认为 3, 这样已经存在的博客会有一个不错的评分。

namespace
MigrationsCodeDemo.Migrations
{
    using System.Data.Entity.Migrations;

    publicpartialclass AddPostClass : DbMigration
    {
        publicoverridevoid Up()
        {
            CreateTable(
                "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("Blogs", t => t.BlogId, cascadeDelete: true)
                .Index(t => t.BlogId)
                .Index(p => p.Title, unique: true);

            AddColumn("Blogs", "Rating", c => c.Int(nullable: false, defaultValue: 3));
        }

        publicoverridevoid Down()
        {
            DropIndex("Posts", new[] { "BlogId" });
            DropForeignKey("Posts", "BlogId", "Blogs");
            DropColumn("Blogs", "Rating");
            DropTable("Posts");
        }
    }
}
 

4. 运行 Update-Database 提交到数据库,这次可以使用一个参数 -Verbose,以便可以看到生成的 SQL 脚本。

Entity Framework first code

数据操作/定制 SQL

我们已经完成的迁移并没有修改或者移动任何数据,我们可以在迁移中的任何地点运行任意脚本。

1. 在模型上增加一个摘要 PostAbstrack 属性,然后,希望使用已经发布的内容来填充这个摘要属性。

public
class
Post
{
    publicint PostId { get; set; }
    [MaxLength(200)]
    publicstring Title { get; set; }
    publicstring Content { get; set; }
    public string Abstract { get; set; }publicint BlogId { get; set; }
    public Blog Blog { get; set; }
}
 

2. 创建一个迁移。

Entity Framework first code

3. 修改生成的迁移文件,

namespace
MigrationsCodeDemo.Migrations
{
    using System.Data.Entity.Migrations;
    
    publicpartialclass AddPostAbstract : DbMigration
    {
        publicoverridevoid Up()
        {
            AddColumn("Posts", "Abstract", c => c.String());

            Sql("UPDATE Posts SET Abstract = LEFT(Content, 100) WHERE Abstract IS NULL");

        }
        
        publicoverridevoid Down()
        {
            DropColumn("Posts", "Abstract");
        }
    }
}
 

4. 更新数据库之后,就会得到最新的数据了。使用 Verbose 参数可以看到提交的脚本。

Entity Framework first code


迁移到特定版本(包含降级)

你可以升级或者降级到特定的版本。

假设我们希望数据库迁移到执行 AddBlogUrl 迁移之后的状态,通过 -TargetMigration 参数来降级。

Entity Framework first code

如果你希望回到最初的空数据库,可以使用参数 TargetMigration:$InitialDatabase.

Entity Framework first code

获取迁移的脚本

在运行 Update-Database 的时候,使用参数 -Script 。

-SourceMigration:$InitialDatabase 用来指定起始的版本, -TargetMigration:"AddPostAbstract" 用来指定目标版本。

我们希望取得从初始的数据库,直到迁移到 AddPostAbstract 版本使用的脚本。

Entity Framework first code

执行之后,得到一个脚本文件。

CREATE
TABLE
[Blogs]
(
    [BlogId][int]NOTNULLIDENTITY,
    [Name][nvarchar](max),
    CONSTRAINT[PK_Blogs]PRIMARYKEY ([BlogId])
)
CREATETABLE[__MigrationHistory] (
    [MigrationId][nvarchar](255) NOTNULL,
    [CreatedOn][datetime]NOTNULL,
    [Model][varbinary](max) NOTNULL,
    [ProductVersion][nvarchar](32) NOTNULL,
    CONSTRAINT[PK___MigrationHistory]PRIMARYKEY ([MigrationId])
)
BEGIN TRY
    EXEC sp_MS_marksystemobject '__MigrationHistory'END TRY
BEGIN CATCH
END CATCH
INSERTINTO[__MigrationHistory] ([MigrationId], [CreatedOn], [Model], [ProductVersion]) VALUES ('201202171353373_InitialCreate', '2012-02-17T14:51:25.032Z', 0x1F8B0800000000000400ECBD07601C499625262F6DCA7B7F4AF54AD7E074A10880601324D8904010ECC188CDE692EC1D69472329AB2A81CA6556655D661640CCED9DBCF7DE7BEFBDF7DE7BEFBDF7BA3B9D4E27F7DFFF3F5C6664016CF6CE4ADAC99E2180AAC81F3F7E7C1F3F22FEC7BFF71F7CFC7BBC5B94E9655E3745B5FCECA3DDF1CE4769BE9C56B36279F1D947EBF67CFBE0A3DFE3E8374E1E9FCE16EFD29F34EDF6D08EDE5C369F7D346FDBD5A3BB779BE93C5F64CD78514CEBAAA9CEDBF1B45ADCCD66D5DDBD9D9D83BBBB3B777302F111C14AD3C7AFD6CBB658E4FC07FD79522DA7F9AA5D67E517D52C2F1BFD9CBE79CD50D317D9226F56D934FFECA32F8A8B3A6B098BE684DA3ECD17D547E971596484C9EBBC3C7F4FB4761E02AD8F6C87D4E529A1D65EBFB95EE5DCED671F3D29AB0BBF05B5F9BDF2EBE003FAE8655DADF2BABD7E959F7BEF9DCD3E4AEF86EFDEEDBE6C5FEDBC07143EFBE86CD9DEDBFB287DB12ECB6C52D207E759D9E41FA5AB4F1FBD6EAB3AFF3C5FE644907CF6326BDBBCA6C9399BE53C0425C5A3D5A7B7A3C6C3BB3B7BA0C6DD6CB9AC5AA6710FF90EAAF8D720FABAAD89693E4A9F15EFF2D9F37C79D1CE2DB25F64EFCC27F4EB47E957CB82788C5E6AEB75EE0F4EFEDEDCE95775F9B3DCE7E3BB8E09FAAC41DCDA660551DD9B2F7C96BF6B3B6C22ED5FE7ADD7B2F92875C08567C7CC61510C6C5F4E24EE8A4C18D9B93B203C8FBFC8562B228E274CFA49FA5A24E964FBF5FB4BCB4260DC9D3611A1B1D8DA9E8843B38BBCF32D754D983E2BEAA67D9AB5D924C3749DCC16BD66B7A0ACE9C9277057341DBD4D6BFC2E6FF4D5C9B82FEF0C45DF7D46035A9080F1D8746484474C4DE88BAFA75999D503427E5295EBC57293C2D80445E4CF87219FDC1E020B930F803FE8BFFFF86E67FC5D227B22A32D3B6AAF3B659BB8BDDBC4F66EB9BEC3DD8F95D36EB61F3DD693261FA54498CB6206B67B7DDDB4F9628C06E3D7BFA83C290B1AAF6BF045B62CCEF3A67D53BDCD610B4932BEBE09B24AB76966E5FF9BED500112DC68717A66EAF6F6637999D5D379566F2DB277773EC026BC079CF7D3F37DA575B3B61F54F6C2759F7D349B90FFF2461054F3F035ED405F021EDFF5FDACC74FF3A6B87020E0752DF329749F036ADA9C2DCF2B43621A918F9169D299812FF2369B11618EEBB638CFA62D7D3DCD9B86CDF34F66E59A9A9C2E26F9EC6CF9E5BA5DADDBE3A6C91793F2DA1FEFE3BB9BFB676317E2FCF8CB156BEF6F620884664143C8BF5C3E5917E5CCE2FDACCFCA4320C0232A1F8415B92704EEE2DA427A512D6F0948C9F7345FE54B48D79B7CB12A0958F3E5F27576990FE376330D438A3D7E5A646402173E05E513C5E475463D7B5D5007FE1BAE3FFA93D8959CFCA3FF270000FFFF2B65B379590C0000, '4.3.0')
ALTERTABLE[Blogs]ADD[Url][nvarchar](max)
INSERTINTO[__MigrationHistory] ([MigrationId], [CreatedOn], [Model], [ProductVersion]) VALUES ('201202171413369_AddBlogUrl', '2012-02-17T14:51:25.079Z', 0x1F8B0800000000000400ECBD07601C499625262F6DCA7B7F4AF54AD7E074A10880601324D8904010ECC188CDE692EC1D69472329AB2A81CA6556655D661640CCED9DBCF7DE7BEFBDF7DE7BEFBDF7BA3B9D4E27F7DFFF3F5C6664016CF6CE4ADAC99E2180AAC81F3F7E7C1F3F22FEC7BFF71F7CFC7BBC5B94E9655E3745B5FCECA3DDF1CE4769BE9C56B36279F1D947EBF67CFBE0A3DFE3E8374E1E9FCE16EFD29F34EDF6D08EDE5C369F7D346FDBD5A3BB779BE93C5F64CD78514CEBAAA9CEDBF1B45ADCCD66D5DDBD9D9D83BBBB3B777302F111C14AD3C7AFD6CBB658E4FC07FD79522DA7F9AA5D67E517D52C2F1BFD9CBE79CD50D317D9226F56D934FFECA32F8A8B3A6B098BE684DA3ECD17D547E971596484C9EBBC3C7F4FB4761E02AD8F6C87D4E529A1D65EBFB95EE5DCED671F3D29AB0BBF05B5F9BDF2EBE003FAE8655DADF2BABD7E959F7BEF9DCD3E4AEF86EFDEEDBE6C5FEDBC07143EFBE86CD9DEDBFB287DB12ECB6C52D207E759D9E41FA5AB4F1FBD6EAB3AFF3C5FE644907CF6326BDBBCA6C9399BE53C0425C5A3D5A7B7A3C6C3BB3B7BA0C6DD6CB9AC5AA6710FF90EAAF8D720FABAAD89693E4A9F15EFF2D9F37C79D1CE2DB25F64EFCC27F4EB47E957CB82788C5E6AEB75EE0F4EFEDEDCE95775F9B3DCE7E3BB8E09FAAC41DCDA660551DD9B2F7C96BF6B3B6C22ED5FE7ADD7B2F92875C08567C7CC61510C6C5F4E24EE8A4C18D9B93B203C8FBFC8562B228E274CFA49FA5A24E964FBF5FB4BCB4260DC9D3611A1B1D8DA9E8843B38BBCF32D754D983E2BEAA67D9AB5D924C3749DCC16BD66B7A0ACE9C9277057341DBD4D6BFC2E6FF4D5C9B82FEF0C45DF7D46035A9080F1D8746484474C4DE88BAFA75999D503427E5295EBC57293C2D80445E4CF87219FDC1E020B930F803FE8BFFFF86E67FC5D227B22A32D3B6AAF3B659BB8BDDBC4F66EB9BEC3DD8F95D36EB61F3DD693261FA54498CB6206B67B7DDDB4F9628C06E3D7BFA83C290B1AAF6BF045B62CCEF3A67D53BDCD610B4932BEBE09B24AB76966E5FF9BED500112DC68717A66EAF6F6637999D5D379566F2DB277773EC026BC079CF7D3F37DA575B3B61F54F6C2759F7D349B90FFF2461054F3F035ED405F021EDFF5FDACC74FF3A6B87020E0752DF329749F036ADA9C2DCF2B43621A918F9169D299812FF2369B11618EEBB638CFA62D7D3DCD9B86CDF34F66E59A9A9C2E26F9EC6CF9E5BA5DADDBE3A6C91793F2DA1FEFE3BB9BFB676317E2FCF8CB156BEF6F620884664143C8BF5C3E5917E5CCE2FDACCFCA4320C0232A1F8415B92704EEE2DA427A512D6F0948C9F7345FE54B48D79B7CB12A0958F3E5F27576990FE376330D438A3D7E5A646402173E05E513C5E475463D7B5D5007FE1BAE3FFA93D8959CFCA3FF270000FFFF2B65B379590C0000, '4.3.0')
CREATETABLE[Posts] (
    [PostId][int]NOTNULLIDENTITY,
    [Title][nvarchar](200),
    [Content][nvarchar](max),
    [BlogId][int]NOTNULL,
    CONSTRAINT[PK_Posts]PRIMARYKEY ([PostId])
)
CREATEINDEX[IX_BlogId]ON[Posts]([BlogId])
CREATEUNIQUEINDEX[IX_Title]ON[Posts]([Title])
ALTERTABLE[Blogs]ADD[Rating][int]NOTNULLDEFAULT3ALTERTABLE[Posts]ADDCONSTRAINT[FK_Posts_Blogs_BlogId]FOREIGNKEY ([BlogId]) REFERENCES[Blogs] ([BlogId]) ONDELETECASCADEINSERTINTO[__MigrationHistory] ([MigrationId], [CreatedOn], [Model], [ProductVersion]) VALUES ('201202171424494_AddPostClass', '2012-02-17T14:51:25.092Z', 0x1F8B0800000000000400ECBD07601C499625262F6DCA7B7F4AF54AD7E074A10880601324D8904010ECC188CDE692EC1D69472329AB2A81CA6556655D661640CCED9DBCF7DE7BEFBDF7DE7BEFBDF7BA3B9D4E27F7DFFF3F5C6664016CF6CE4ADAC99E2180AAC81F3F7E7C1F3F22FEC7BFF71F7CFC7BBC5B94E9655E3745B5FCECA3DDF1CE4769BE9C56B36279F1D947EBF67CFBE0A3DFE3E8374E1E9FCE16EFD29F34EDF6D08EDE5C369F7D346FDBD5A3BB779BE93C5F64CD78514CEBAAA9CEDBF1B45ADCCD66D5DDBD9D9D83BBBB3B777302F111C14AD3C7AFD6CBB658E4FC07FD79522DA7F9AA5D67E517D52C2F1BFD9CBE79CD50D317D9226F56D934FFECA32F8A8B3A6B098BE684DA3ECD17D547E971596484C9EBBC3C7F4FB4761E02AD8F6C87D4E529A1D65EBFB95EE5DCED671F3D29AB0BBF05B5F9BDF2EBE003FAE8655DADF2BABD7E959F7BEF9DCD3E4AEF86EFDEEDBE6C5FEDBC07143EFBE86CD9DEDBFB287DB12ECB6C52D207E759D9E41FA5AB4F1FBD6EAB3AFF3C5FE644907CF6326BDBBCA6C9399BE53C0425C5A3D5A7B7A3C6C3BB3B7BA0C6DD6CB9AC5AA6710FF90EAAF8D720FABAAD89693E4A9F15EFF2D9F37C79D1CE2DB25F64EFCC27F4EB47E957CB82788C5E6AEB75EE0F4EFEDEDCE95775F943EFF31591031D6D9E930E8C17D96571C174EC407B59356DF351FA2A2F8593E7C54AB8778C6F7E7F66B8F4595D2D5E55A536E70F7FFF37597D91B78446D5FDE675B5AEA71D141EDF75BCBC91C301E6EB7038DEFB3A1C6EDEFBFF0087BF29DAF27D599C7AFA40762385D8D210DFB3DF0F67F3DBA99EDBB2B9F0F1FB73B9E1E53E971BFEBF0D971F374D352DB86B8FEDA4DB7000A7CB593A88834C80C19AE8BD2EDB62551653EAF2B38FBED5A3460C98155B074C461F02DB0DF122605F2E9FE665DEE6E9F114E320C6C89A6936EBCF01D160167E42529AD71093AC246E6ADA3A2B966D5FA48BE5B45865E510CA9D17DEC3CE01290BBEFBCDD37C952F21C44374FFB07E2DF80E916EA2C9E3BB1ED3F43526A492DEC86B0F0196D4775DED29ED5FE7ADD79214BE63D4800B7A1C14BEACD6A2F7B2F063E7656F0021049537EFFB9E3076E9B8492E2C9216BFDE346C9204EF75A54D97A1C38144E4DDCE86FDEEF15D7117F583C77707FCCAC75F64AB152954CFCFD44FD2D7E2649E6CBF7E7F47722130EE4E9B883F69B1B53D9169CB2EF2CEB750FDB3FC595137EDD3ACCD2619F4EDC96CD16B760BDE333DF92CD89F23C354A6357E9737FA9EF63