下面全部内容来源于MSDN:
http://msdn.microsoft.com/en-us/data/jj591621.aspx
This walkthrough will provide an overview Code First Migrations in Entity Framework. You can either complete the entire walkthrough or skip to the topic you are interested in. The following topics are covered:
Before we start using migrations we need a project and a Code First model to work with. For this walkthrough we are going to use the canonical Blog and Post model.
- using System.Data.Entity;
- using System.Collections.Generic;
- using System.ComponentModel.DataAnnotations;
- using System.Data.Entity.Infrastructure;
-
- namespace MigrationsDemo
- {
- public class BlogContext : DbContext
- {
- public DbSet<Blog> Blogs { get; set; }
- }
-
- public class Blog
- {
- public int BlogId { get; set; }
- public string Name { get; set; }
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
-
- namespace MigrationsDemo
- {
- class Program
- {
- 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();
- }
- }
- }
It’s time to make some more changes to our model.
- public string Url { get; set; }
If you were to run the application again you would get an InvalidOperationException stating 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).
As the exception suggests, it’s time to start using Code First Migrations. The first step is to enable migrations for our context.
This command has added a Migrations folder to our project, this new folder contains two files:
Code First Migrations has two primary commands that you are going to become familiar with.
We need to scaffold a migration to take care of the new Url property we have added. The Add-Migration command allows us to give these migrations a name, let’s just call ours AddBlogUrl.
- namespace MigrationsDemo.Migrations
- {
- using System;
- using System.Data.Entity.Migrations;
-
- public partial class AddBlogUrl : DbMigration
- {
- public override void Up()
- {
- AddColumn("Blogs", "Url", c => c.String());
- }
-
- public override void Down()
- {
- DropColumn("Blogs", "Url");
- }
- }
- }
We could now edit or add to this migration but everything looks pretty good. Let’s use Update-Database to apply this migration to the database.
The MigrationsDemo.BlogContext database is now updated to include the Url column in the Blogs table.
So far we’ve generated and run a migration without making any changes. Now let’s look at editing the code that gets generated by default.
- public int Rating { 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; }
- }
- public virtual List<Post> Posts { get; set; }
We'll use the Add-Migration command to let Code First Migrations scaffold its best guess at the migration for us. We’re going to call this migration AddPostClass.
Code First Migrations did a pretty good job of scaffolding these changes, but there are some things we might want to change:
- namespace MigrationsCodeDemo.Migrations
- {
- using System;
- using System.Data.Entity.Migrations;
-
- public partial class AddPostClass : DbMigration
- {
- public override void 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));
- }
-
- public override void Down()
- {
- DropIndex("Posts", new[] { "Title" });
- DropIndex("Posts", new[] { "BlogId" });
- DropForeignKey("Posts", "BlogId", "Blogs");
- DropColumn("Blogs", "Rating");
- DropTable("Posts");
- }
- }
- }
Our edited migration is ready to go, so let’s use Update-Database to bring the database up-to-date. This time let’s specify the –Verbose flag so that you can see the SQL that Code First Migrations is running.
So far we have looked at migration operations that don’t change or move any data, now let’s look at something that needs to move some data around. There is no native support for data motion yet, but we can run some arbitrary SQL commands at any point in our script.
- public string Abstract { get; set; }
We'll use the Add-Migration command to let Code First Migrations scaffold its best guess at the migration for us.
- namespace MigrationsCodeDemo.Migrations
- {
- using System;
- using System.Data.Entity.Migrations;
-
- public partial class AddPostAbstract : DbMigration
- {
- public override void Up()
- {
- AddColumn("Posts", "Abstract", c => c.String());
-
- Sql("UPDATE Posts SET Abstract = LEFT(Content, 100) WHERE Abstract IS NULL");
- }
-
- public override void Down()
- {
- DropColumn("Posts", "Abstract");
- }
- }
- }
Our edited migration looks good, so let’s use Update-Database to bring the database up-to-date. We’ll specify the –Verbose flag so that we can see the SQL being run against the database.
So far we have always upgraded to the latest migration, but there may be times when you want upgrade/downgrade to a specific migration.
Let’s say we want to migrate our database to the state it was in after running our AddBlogUrl migration. We can use the –TargetMigration switch to downgrade to this migration.
This command will run the Down script for our AddBlogAbstract and AddPostClass migrations.
If you want to roll all the way back to an empty database then you can use the Update-Database –TargetMigration: $InitialDatabase command.
If another developer wants these changes on their machine they can just sync once we check our changes into source control. Once they have our new migrations they can just run the Update-Database command to have the changes applied locally. However if we want to push these changes out to a test server, and eventually production, we probably want a SQL script we can hand off to our DBA.
Code First Migrations will run the migration pipeline but instead of actually applying the changes it will write them out to a .sql file for you. Once the script is generated, it is opened for you in Visual Studio, ready for you to view or save.
If you are deploying your application you may want it to automatically upgrade the database (by applying any pending migrations) when the application launches. You can do this by registering the MigrateDatabaseToLatestVersion database initializer. A database initializer simply contains some logic that is used to make sure the database is setup correctly. This logic is run the first time the context is used within the application process (AppDomain).
We can update the Program.cs file, as shown below, to set the MigrateDatabaseToLatestVersion initializer for BlogContext before we use the context (Line 14). Note that you also need to add a using statement for the System.Data.Entity namespace (Line 5).
When we create an instance of this initializer we need to specify the context type (BlogContext) and the migrations configuration (Configuration) - the migrations configuration is the class that got added to our Migrations folder when we enabled Migrations.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Data.Entity;
- 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();
- }
- }
- }
Now whenever our application runs it will first check if the database it is targeting is up-to-date, and apply any pending migrations if it is not.
In this walkthrough you saw how to scaffold, edit and run code-based migrations to upgrade and downgrade your database. You also saw how to get a SQL script to apply migrations to a database and how to have any pending migrations automatically applied on application startup.