当 Entity Framework Code First 的数据模型发生改变时,默认会引发一个System.InvalidOperationException 的异常。解决方法是使用DropCreateDatabaseAlways 或DropCreateDatabaseIfModelChanges,让Entity Framework 自动将数据库删除,然后重新创建。不过,这种方式过于残暴,应该使用更人性化的方式,让Entity Framework 帮助我们自动调整数据库架构。并且仍然保留现有数据库中的数据。而这种开发技术就是  Code First 数据库迁移(DB Migration)。

首先,我们先用 Code First 方式建立一个简单的ASP.NET MVC4 应用程序

在Models 文件夹下建立两个实体类Member、Guestbook。

Member 实体类定义如下:

  1. namespace CodeFirstDemo.Models
  2. {
  3. public partial class Member
  4. {
  5. public Member()
  6. {
  7. this.Guestbooks = new List<Guestbook>();
  8. }
  9. public int Id { get; set; }
  10. public string Name { get; set; }
  11. public string Email { get; set; }
  12. public virtual ICollection<Guestbook> Guestbooks { get; set; }
  13. }
  14. }
namespace CodeFirstDemo.Models
{
public partial class Member
{
public Member()
{
this.Guestbooks = new List<Guestbook>();
} public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public virtual ICollection<Guestbook> Guestbooks { get; set; }
}
}

Guestbook 实体类定义如下:

  1. namespace CodeFirstDemo.Models
  2. {
  3. public partial class Guestbook
  4. {
  5. public int Id { get; set; }
  6. public string Message { get; set; }
  7. public System.DateTime CreatedOn { get; set; }
  8. public int MemberId { get; set; }
  9. public virtual Member Member { get; set; }
  10. }
  11. }
namespace CodeFirstDemo.Models
{
public partial class Guestbook
{
public int Id { get; set; }
public string Message { get; set; }
public System.DateTime CreatedOn { get; set; }
public int MemberId { get; set; }
public virtual Member Member { get; set; }
}
}

在Models 文件夹下建立Mapping 文件夹,并建立对应实体类的关系映射类MemberMap 、GuestbookMap

MemberMap 类定义如下:

  1. namespace CodeFirstDemo.Models.Mapping
  2. {
  3. public class MemberMap : EntityTypeConfiguration<Member>
  4. {
  5. public MemberMap()
  6. {
  7. // Primary Key
  8. this.HasKey(t => t.Id);
  9. // Properties
  10. this.Property(t => t.Id)
  11. .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
  12. this.Property(t => t.Name)
  13. .IsRequired()
  14. .HasMaxLength(10);
  15. this.Property(t => t.Email)
  16. .IsRequired()
  17. .HasMaxLength(200);
  18. // Table & Column Mappings
  19. this.ToTable("Member");
  20. this.Property(t => t.Id).HasColumnName("Id");
  21. this.Property(t => t.Name).HasColumnName("Name");
  22. this.Property(t => t.Email).HasColumnName("Email");
  23. }
  24. }
  25. }
namespace CodeFirstDemo.Models.Mapping
{
public class MemberMap : EntityTypeConfiguration<Member>
{
public MemberMap()
{
// Primary Key
this.HasKey(t => t.Id); // Properties
this.Property(t => t.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); this.Property(t => t.Name)
.IsRequired()
.HasMaxLength(10); this.Property(t => t.Email)
.IsRequired()
.HasMaxLength(200); // Table & Column Mappings
this.ToTable("Member");
this.Property(t => t.Id).HasColumnName("Id");
this.Property(t => t.Name).HasColumnName("Name");
this.Property(t => t.Email).HasColumnName("Email");
}
}
}

GuestbookMap 类定义如下:

  1. namespace CodeFirstDemo.Models.Mapping
  2. {
  3. public class GuestbookMap : EntityTypeConfiguration<Guestbook>
  4. {
  5. public GuestbookMap()
  6. {
  7. // Primary Key
  8. this.HasKey(t => t.Id);
  9. // Properties
  10. this.Property(t => t.Message)
  11. .IsRequired()
  12. .HasMaxLength(200);
  13. // Table & Column Mappings
  14. this.ToTable("Guestbook");
  15. this.Property(t => t.Id).HasColumnName("Id");
  16. this.Property(t => t.Message).HasColumnName("Message");
  17. this.Property(t => t.CreatedOn).HasColumnName("CreatedOn");
  18. this.Property(t => t.MemberId).HasColumnName("MemberId");
  19. // Relationships
  20. this.HasRequired(t => t.Member)
  21. .WithMany(t => t.Guestbooks)
  22. .HasForeignKey(d => d.MemberId);
  23. }
  24. }
  25. }
namespace CodeFirstDemo.Models.Mapping
{
public class GuestbookMap : EntityTypeConfiguration<Guestbook>
{
public GuestbookMap()
{
// Primary Key
this.HasKey(t => t.Id); // Properties
this.Property(t => t.Message)
.IsRequired()
.HasMaxLength(200); // Table & Column Mappings
this.ToTable("Guestbook");
this.Property(t => t.Id).HasColumnName("Id");
this.Property(t => t.Message).HasColumnName("Message");
this.Property(t => t.CreatedOn).HasColumnName("CreatedOn");
this.Property(t => t.MemberId).HasColumnName("MemberId"); // Relationships
this.HasRequired(t => t.Member)
.WithMany(t => t.Guestbooks)
.HasForeignKey(d => d.MemberId); }
}
}

在Models 建立数据库上下文类CodeFirstDemoContext

CodeFirstDemoContext 类定义如下:

  1. namespace CodeFirstDemo.Models
  2. {
  3. public partial class CodeFirstDemoContext : DbContext
  4. {
  5. static CodeFirstDemoContext()
  6. {
  7. //Database.SetInitializer<CodeFirstDemoContext>(new DropCreateDatabaseIfModelChanges<CodeFirstDemoContext>());
  8. }
  9. public CodeFirstDemoContext()
  10. : base("Name=CodeFirstDemoContext")
  11. {
  12. }
  13. public DbSet<Guestbook> Guestbooks { get; set; }
  14. public DbSet<Member> Members { get; set; }
  15. protected override void OnModelCreating(DbModelBuilder modelBuilder)
  16. {
  17. modelBuilder.Configurations.Add(new GuestbookMap());
  18. modelBuilder.Configurations.Add(new MemberMap());
  19. }
  20. }
  21. }
namespace CodeFirstDemo.Models
{
public partial class CodeFirstDemoContext : DbContext
{
static CodeFirstDemoContext()
{
//Database.SetInitializer<CodeFirstDemoContext>(new DropCreateDatabaseIfModelChanges<CodeFirstDemoContext>());
} public CodeFirstDemoContext()
: base("Name=CodeFirstDemoContext")
{
} public DbSet<Guestbook> Guestbooks { get; set; }
public DbSet<Member> Members { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new GuestbookMap());
modelBuilder.Configurations.Add(new MemberMap());
}
}
}

Models 文件夹结构下

以上就是一个简单的 Code First 结构了

接下来在Web.config 添加数据库连接字符串

  1. <connectionStrings>
  2. <add name="CodeFirstDemoContext" connectionString="Data Source=vin-pc;Initial Catalog=CodeFirstDemo;Persist Security Info=True;User ID=sa;Password=123456;MultipleActiveResultSets=True"
  3. providerName="System.Data.SqlClient" />
  4. </connectionStrings>
<connectionStrings>
<add name="CodeFirstDemoContext" connectionString="Data Source=vin-pc;Initial Catalog=CodeFirstDemo;Persist Security Info=True;User ID=sa;Password=123456;MultipleActiveResultSets=True"
providerName="System.Data.SqlClient" />
</connectionStrings>

然后添加一个控制器HomeController

  1. namespace CodeFirstDemo.Controllers
  2. {
  3. public class HomeController : Controller
  4. {
  5. //
  6. // GET: /Home/
  7. public ActionResult Index()
  8. {
  9. CodeFirstDemoContext db = new CodeFirstDemoContext();
  10. Member member = new Member { Name = "tt", Email = "qwe@qq.com" };
  11. db.Members.Add(member);
  12. db.SaveChanges();
  13. return View();
  14. }
  15. }
  16. }
namespace CodeFirstDemo.Controllers
{
public class HomeController : Controller
{
//
// GET: /Home/ public ActionResult Index()
{
CodeFirstDemoContext db = new CodeFirstDemoContext();
Member member = new Member { Name = "tt", Email = "qwe@qq.com" };
db.Members.Add(member);
db.SaveChanges(); return View();
} }
}

EF Code First 如何记录版本

当应用程序通过EF Code First 创建数据库后,在此数据库中讲会自动创建一个名为 dbo. __MigrationHistory 的系统数据表,如下图所示:

打开dbo. __MigrationHistory 会发现三个字段:MigrationId 字段用来记录这次由 EFCode First 所创建的一个表示名称,也可以称为一个版本代码;Model 字段表示这次创建时的模型数据,这是由 Entity Framework 将所有数据模型串行化后的版本,所以看不出是什么;ProductVersion 字段表示当前使用的Entity Framework 版本,如下图所示:

如果尚未启用数据库迁移功能,每次在应用程序运行时,都会对比程序中当前的数据模型,与数据库中dbo. __MigrationHistory 表的Model 字段中的值是否一致,如果不一致,默认就会发生异常。

如果启用数据库迁移功能之后,这个表就会开始记录每次数据模型变动的记录与版本。

启用数据库迁移

若要在项目中启用数据库迁移功能,必须先开启程序包管理器控制台(Package Manager Console)窗口,然后输入 Enable-Migrations指令,如下图:

运行 Enable-Migrations 指令的过程中, Visual Studio 会在项目里创建一个Migrations 目录,该目录下还创建有两个文件,201309120825043_InitialCreate.cs 、Configuration.cs,如下图:

1.      201309120825043_InitialCreate.cs

在启用数据库迁移之前,由于已经通过 Code First 在数据库中创建好了相关的数据库结构,也创建了一个初始的dbo. __MigrationHistory 数据表,表中也有一条数据,这条数据的MigrationId值正好会等于文档名。VS会将dbo. __MigrationHistory 表的Model 值读出,并创建这个类的属性,其属性就是包含那次数据模型的完整描述。

  1. namespace CodeFirstDemo.Migrations
  2. {
  3. using System;
  4. using System.Data.Entity.Migrations;
  5. public partial class InitialCreate : DbMigration
  6. {
  7. public override void Up()
  8. {
  9. CreateTable(
  10. "dbo.Guestbook",
  11. c => new
  12. {
  13. Id = c.Int(nullable: false, identity: true),
  14. Message = c.String(nullable: false, maxLength: 200),
  15. CreatedOn = c.DateTime(nullable: false),
  16. MemberId = c.Int(nullable: false),
  17. })
  18. .PrimaryKey(t => t.Id)
  19. .ForeignKey("dbo.Member", t => t.MemberId, cascadeDelete: true)
  20. .Index(t => t.MemberId);
  21. CreateTable(
  22. "dbo.Member",
  23. c => new
  24. {
  25. Id = c.Int(nullable: false, identity: true),
  26. Name = c.String(nullable: false, maxLength: 5),
  27. Email = c.String(nullable: false, maxLength: 200),
  28. })
  29. .PrimaryKey(t => t.Id);
  30. }
  31. public override void Down()
  32. {
  33. DropIndex("dbo.Guestbook", new[] { "MemberId" });
  34. DropForeignKey("dbo.Guestbook", "MemberId", "dbo.Member");
  35. DropTable("dbo.Member");
  36. DropTable("dbo.Guestbook");
  37. }
  38. }
  39. }
namespace CodeFirstDemo.Migrations
{
using System;
using System.Data.Entity.Migrations; public partial class InitialCreate : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.Guestbook",
c => new
{
Id = c.Int(nullable: false, identity: true),
Message = c.String(nullable: false, maxLength: 200),
CreatedOn = c.DateTime(nullable: false),
MemberId = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.Member", t => t.MemberId, cascadeDelete: true)
.Index(t => t.MemberId); CreateTable(
"dbo.Member",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(nullable: false, maxLength: 5),
Email = c.String(nullable: false, maxLength: 200),
})
.PrimaryKey(t => t.Id); } public override void Down()
{
DropIndex("dbo.Guestbook", new[] { "MemberId" });
DropForeignKey("dbo.Guestbook", "MemberId", "dbo.Member");
DropTable("dbo.Member");
DropTable("dbo.Guestbook");
}
}
}

2.      Configuration.cs

这个类定义了运行数据库迁移时该有的行为。默认情况下,数据库并不会发生迁移动作,除非将 Configuration() 内的 AutomaticMigrationsEnabled 改为 true,才会让 CodeFirst 自动迁移数据库。

  1. namespace CodeFirstDemo.Migrations
  2. {
  3. using System;
  4. using System.Data.Entity;
  5. using System.Data.Entity.Migrations;
  6. using System.Linq;
  7. internal sealed class Configuration : DbMigrationsConfiguration<CodeFirstDemo.Models.CodeFirstDemoContext>
  8. {
  9. public Configuration()
  10. {
  11. AutomaticMigrationsEnabled = false;
  12. }
  13. protected override void Seed(CodeFirstDemo.Models.CodeFirstDemoContext context)
  14. {
  15. //  This method will be called after migrating to the latest version.
  16. //  You can use the DbSet<T>.AddOrUpdate() helper extension method
  17. //  to avoid creating duplicate seed data. E.g.
  18. //
  19. //    context.People.AddOrUpdate(
  20. //      p => p.FullName,
  21. //      new Person { FullName = "Andrew Peters" },
  22. //      new Person { FullName = "Brice Lambson" },
  23. //      new Person { FullName = "Rowan Miller" }
  24. //    );
  25. //
  26. }
  27. }
  28. }
namespace CodeFirstDemo.Migrations
{
using System;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq; internal sealed class Configuration : DbMigrationsConfiguration<CodeFirstDemo.Models.CodeFirstDemoContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
} protected override void Seed(CodeFirstDemo.Models.CodeFirstDemoContext 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" }
// );
//
}
}
}

运行数据库迁移

下面来更改 Member 的数据模型,添加两个字段,分别是 UserName 和 Password 属性。

  1. namespace CodeFirstDemo.Models
  2. {
  3. public partial class Member
  4. {
  5. public Member()
  6. {
  7. this.Guestbooks = new List<Guestbook>();
  8. }
  9. public int Id { get; set; }
  10. public string Name { get; set; }
  11. public string Email { get; set; }
  12. public string UserName { get; set; }
  13. public string Password { get; set; }
  14. public virtual ICollection<Guestbook> Guestbooks { get; set; }
  15. }
  16. }
namespace CodeFirstDemo.Models
{
public partial class Member
{
public Member()
{
this.Guestbooks = new List<Guestbook>();
} public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public virtual ICollection<Guestbook> Guestbooks { get; set; }
}
}

通过Package Manager Console 输入 Add-Migration 指令,来新增一条数据库迁移版本,输入时必须带上一个“版本名称”参数。例如,想要取名为AddUsernamePassword,则可以输入以下指令:

运行完成后,会在 Migrations 文件夹新增一个文件,如下图:

这次运行 Add-Migration 指令,所代表的意思就是新增一次运行数据库迁移命令,VS2012会自动对比当前数据库中的 Model 定义与当前更改过的数据模型,并将差异的字段变化写入这个自动新增的类内,程序代码如下:

  1. namespace CodeFirstDemo.Migrations
  2. {
  3. using System;
  4. using System.Data.Entity.Migrations;
  5. public partial class AddUsernamePassword : DbMigration
  6. {
  7. public override void Up()
  8. {
  9. AddColumn("dbo.Member", "UserName", c => c.String());
  10. AddColumn("dbo.Member", "Password", c => c.String());
  11. }
  12. public override void Down()
  13. {
  14. DropColumn("dbo.Member", "Password");
  15. DropColumn("dbo.Member", "UserName");
  16. }
  17. }
  18. }
namespace CodeFirstDemo.Migrations
{
using System;
using System.Data.Entity.Migrations; public partial class AddUsernamePassword : DbMigration
{
public override void Up()
{
AddColumn("dbo.Member", "UserName", c => c.String());
AddColumn("dbo.Member", "Password", c => c.String());
} public override void Down()
{
DropColumn("dbo.Member", "Password");
DropColumn("dbo.Member", "UserName");
}
}
}

NOTES

每一次新增数据库迁移版本,其类内都会包含一个Up() 方法与 Down() 方法,所代表的意思分别是“升级数据库”与“降级数据库”的动作,所以,数据库迁移不仅仅只是将数据库升级,还可以恢复到旧版本。

当前还没有对数据库做任何迁移动作,所以数据库中的数据结构并没有任何改变,现在,手动在 Member 数据表中输入几条数据,以确认待会儿数据库迁移(升级)之后数据是否消失,如图:

接着,对数据库进行迁移动作,在程序包管理控制台(Package Manager Console)窗口中输入Update-Database指令,如图:

更新数据库成功之后,可以查看 Member  数据表结构是否发生变化,以及数据表原来的数据是否存在:

NOTES

我们都知道,在客户端数据库通常是无法直接联机的,客户的生产环境通常也没有安装VS2012,那么如果数据库迁移动作要进行套用时,应该怎么办呢?可以通过 Update-Database 指令的其他参数自动生产数据库迁移的 T-SQL 脚本,然后携带 T-SQL 脚本文件到正式主机部署或更新即可。

Update-Database 指令的–SourceMigration 参数可以指定来源斑斑驳驳,-Targetigration 参数可以指定目标版本, -Script 参数可以用来输出 T-SQL 脚本。以下是生成本次数据库迁移(升级)的 T-SQL 指令演示:

Update-Database –SourceMigration201309120825043_InitialCreate –TargetMigration 201309130055351_AddUsernamePassword-Script

如果要生成数据库降级的 T-SQL,则不能使用–SourceMigration 参数,直接指定–TargetMigration 参数即可,演示如下:

Update-Database –TargetMigration201309120825043_InitialCreate –Script

如果要还原数据库带添加 Code First 之前的初始状态,可以输入以下指令:

Update-Database  -TragetMigration:$InitialDatabase –Script

自定义数据库迁移规则

当了解数据库迁移的规则之后,如果希望在数据库迁移的过程中进行一些微调,例如, Entity Framework 并不支持自动设置字段的默认值,假设我们在 Member 数据模型中想添加一个新的 CreatedOn 属性表示会员的注册日期,并且希望在数据库中自动加上 getdate() 默认值,这时就必须要自定义数据库迁移的规则。

首先更改 Member 数据模型,加上 CreatedOn 属性

Member.cs

  1. namespace CodeFirstDemo.Models
  2. {
  3. public partial class Member
  4. {
  5. public Member()
  6. {
  7. this.Guestbooks = new List<Guestbook>();
  8. }
  9. public int Id { get; set; }
  10. public string Name { get; set; }
  11. public string Email { get; set; }
  12. public string UserName { get; set; }
  13. public string Password { get; set; }
  14. public DateTime CreatedOn { get; set; }
  15. public virtual ICollection<Guestbook> Guestbooks { get; set; }
  16. }
  17. }
namespace CodeFirstDemo.Models
{
public partial class Member
{
public Member()
{
this.Guestbooks = new List<Guestbook>();
} public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public DateTime CreatedOn { get; set; }
public virtual ICollection<Guestbook> Guestbooks { get; set; }
}
}

MemberMap.cs

  1. namespace CodeFirstDemo.Models.Mapping
  2. {
  3. public class MemberMap : EntityTypeConfiguration<Member>
  4. {
  5. public MemberMap()
  6. {
  7. // Primary Key
  8. this.HasKey(t => t.Id);
  9. // Properties
  10. this.Property(t => t.Id)
  11. .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
  12. this.Property(t => t.Name)
  13. .IsRequired()
  14. .HasMaxLength(10);
  15. this.Property(t => t.Email)
  16. .IsRequired()
  17. .HasMaxLength(200);
  18. this.Property(t => t.CreatedOn)
  19. .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
  20. // Table & Column Mappings
  21. this.ToTable("Member");
  22. this.Property(t => t.Id).HasColumnName("Id");
  23. this.Property(t => t.Name).HasColumnName("Name");
  24. this.Property(t => t.Email).HasColumnName("Email");
  25. }
  26. }
  27. }
namespace CodeFirstDemo.Models.Mapping
{
public class MemberMap : EntityTypeConfiguration<Member>
{
public MemberMap()
{
// Primary Key
this.HasKey(t => t.Id); // Properties
this.Property(t => t.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); this.Property(t => t.Name)
.IsRequired()
.HasMaxLength(10); this.Property(t => t.Email)
.IsRequired()
.HasMaxLength(200); this.Property(t => t.CreatedOn)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed); // Table & Column Mappings
this.ToTable("Member");
this.Property(t => t.Id).HasColumnName("Id");
this.Property(t => t.Name).HasColumnName("Name");
this.Property(t => t.Email).HasColumnName("Email");
}
}
}

然后运行一次 Add-Migration指令,并指定版本名称为 AddMemberCreatedOn

这时,再 Migrations 目录下多出一个201309130144538_AddMemberCreatedOn.cs 文件

  1. namespace CodeFirstDemo.Migrations
  2. {
  3. using System;
  4. using System.Data.Entity.Migrations;
  5. public partial class AddMemberCreatedOn : DbMigration
  6. {
  7. public override void Up()
  8. {
  9. AddColumn("dbo.Member", "CreatedOn", c => c.DateTime(nullable: false));
  10. }
  11. public override void Down()
  12. {
  13. DropColumn("dbo.Member", "CreatedOn");
  14. }
  15. }
  16. }
namespace CodeFirstDemo.Migrations
{
using System;
using System.Data.Entity.Migrations; public partial class AddMemberCreatedOn : DbMigration
{
public override void Up()
{
AddColumn("dbo.Member", "CreatedOn", c => c.DateTime(nullable: false));
} public override void Down()
{
DropColumn("dbo.Member", "CreatedOn");
}
}
}

这次我们用不一样的参数来运行数据库迁移,加上–Script 参数,Update-Database –Script

运行完后,会输出完整的数据库更新 T-SQL 脚本,其中第一行就是在 Member 数据表中新增一个 CreatedOn 字段,而且会看到该字段已经给予‘1900-01-01T00:00:00.000’ 这个默认值。第二行则是在 _MigrationHistory新增一条版本记录,如下图:

此时,可以自定义201309130144538_AddMemberCreatedOn.cs 类里的 Up() 方法,在新增字段的地方改用Sql()方法,传入一段自定义的 T-SQL 脚本来创建字段,并改用自己的方法新增字段,如此一来,即可让数据库迁移在升级是自动加上此字段的默认值。

  1. public override void Up()
  2. {
  3. //AddColumn("dbo.Member", "CreatedOn", c => c.DateTime(nullable: false));
  4. Sql("ALTER TABLE [dbo].[Member] ADD [CreatedOn] [datetime] NOT NULL DEFAULT getdate()");
  5. }
public override void Up()
{
//AddColumn("dbo.Member", "CreatedOn", c => c.DateTime(nullable: false));
Sql("ALTER TABLE [dbo].[Member] ADD [CreatedOn] [datetime] NOT NULL DEFAULT getdate()");
}

最后,运行 Update-Database 指令,这是再去检查 Member 数据表,可以看到,数据库迁移升级后的 CreatedOn 字段拥有了我们想要的 getdate() 默认值,如下图:

TIPS

在数据库迁移类中除了有 Up() 方法外,还有 Down() 方法,必须留意当降级时必要的架构的变更动作,如果自定义数据库迁移的规则写不好,可能会导致降级失败或数据库结构紊乱

自动数据库迁移

如果要启用自动数据库迁移的话,在Database.SetInitializer() 方法中使用System.Data.Entity.MigrateDatabaseToLatestVersion泛型类型,并且传入两个参数,第一个是数据上下文类,第二个是在启用数据库迁移时自动生成的 Configuration 类,这个类喂鱼 Migrations 目录下,所以记得要加上命名空间:

  1. Database.SetInitializer(new MigrateDatabaseToLatestVersion<CodeFirstDemoContext, Migrations.Configuration>());
Database.SetInitializer(new MigrateDatabaseToLatestVersion<CodeFirstDemoContext, Migrations.Configuration>());

接着再开启Migrations\Configuration.cs 设置AutomaticMigrationsEnbaled 属性为 ture 即可

  1. AutomaticMigrationsEnabled = true;
AutomaticMigrationsEnabled = true;

如此一来,日后所以的数据模型变动时,都会通过数据库迁移功能自动升级数据库,当每次自动升级发生时,也会在 dbo._MigrationHistory 系统数据表里记录,并以AutomaticMigration 命名,如下图:

如何避免数据库被自动创建或自动迁移

如果想要避免数据库被自动创建或自动迁移,则修改Database.SetInitializer() 方法,如:

  1. Database.SetInitializer<CodeFirstDemoContext>(null);
Database.SetInitializer<CodeFirstDemoContext>(null);

即可避免数据库被自动创建或自动迁移。

使用 Code First 数据库迁移的更多相关文章

  1. Entity Framework 5.0系列之Code First数据库迁移

    我们知道无论是"Database First"还是"Model First"当模型发生改变了都可以通过Visual Studio设计视图进行更新,那么对于Cod ...

  2. 3.3 使用Code First数据库迁移

    当Entity Framework Code First的数据模型发生异动时,默认会引发一个System.InvalidOpertaionException异常.一种解决方法是在Global.asax ...

  3. Code First 数据库迁移

    当 Entity Framework Code First 的数据模型发生改变时,默认会引发一个System.InvalidOperationException 的异常.解决方法是使用DropCrea ...

  4. MVC VS2012 Code First 数据库迁移教程

    1.在“服务资源管理器”连接数据库 2.打开工具-Nuget程序包管理器“程序包管理器控制台” 3.控制台输入命令:PM> Enable-Migrations -StartUpProjectNa ...

  5. ASP.NET MVC 4下 Code First 数据库迁移

     一.命令开启 1.打开控制台:视图->其他窗口->程序包管理器控制台: 2.启动数据库迁移,执行命令:enable-migrations 创建成功后会新增migrations目录等. 若 ...

  6. Code First数据库迁移

    生成数据库 修改类文件PortalContext.cs的静态构造函数,取消当数据库模型发生改变时删除当前数据库重建新数据库的设置. PortalContext() { Database.SetInit ...

  7. EF Code First 数据库迁移Migration剖析

    1.简介 Entity Framework 的Code First 方式,提供了一种方式:编写模型Model,生成模型变更,根据模型变更修改数据库. 而其所以来的环境就是强大的Nuget,如果还在是V ...

  8. [翻译][MVC 5 + EF 6] 5:Code First数据库迁移与程序部署

    原文:Code First Migrations and Deployment with the Entity Framework in an ASP.NET MVC Application 1.启用 ...

  9. Asp.net Mvc Entity Framework Code First 数据库迁移

    1.创建Mvc项目 2.安装Entity Framework 2.1.如下图打开程序包管理器控制台: 2.2.输入命令Install-Package EntityFramework,即可安装Entit ...

随机推荐

  1. OpenFOAM计算结果转换到CFD-Post当中处理

    我们编写如下的Python代码 源代码:

  2. VS2019(NET Core 3.0)发布单文件可执行程序

    NET Core 3.0 发布单文件可执行程序 两种方法. 一.右击vs编辑项目文件,增加PublishSingleFile节点配置,代码如下: <Project Sdk="Micro ...

  3. [Beta]第二次 Scrum Meeting

    [Beta]第二次 Scrum Meeting 写在前面 会议时间 会议时长 会议地点 2019/5/6 22:00 30min 大运村公寓6F楼道 附Github仓库:WEDO 例会照片 工作情况总 ...

  4. 【软工实践】Alpha冲刺(6/6)

    链接部分 队名:女生都队 组长博客: 博客链接 作业博客:博客链接 小组内容 恩泽(组长) 过去两天完成了哪些任务 描述 tomcat的学习与实现 服务器后端部署,API接口的beta版实现 后端代码 ...

  5. uniapp - 键盘弹起背景图片不会被挤压

    [释义] uni.getSystemInfoSync()获取屏幕可用高度windowScreen做为背景图高度即可(非虚拟DOM也可以使用本思路). [源码] <template> < ...

  6. phpstudy5.6 No input file specified的解决方法

    一.问题描述 5.6就提示这个错误,切换5.5就可以 二.原因分析 原因1:提示:“No input file specified.”原因在于使用的PHP5.6是fast_cgi模式,而在某些情况下, ...

  7. GIS地理工具案例教程——批量合并影像-批量镶嵌栅格

    GIS地理工具案例教程--批量合并影像-批量镶嵌栅格 商务合作,科技咨询,版权转让:向日葵,135-4855__4328,xiexiaokui#qq.com 关键词:批量.迭代.循环.自动.智能.地理 ...

  8. Java基础 三目运算符 用if-else对其进行解释

        JDK :OpenJDK-11      OS :CentOS 7.6.1810      IDE :Eclipse 2019‑03 typesetting :Markdown   code ...

  9. 手机端rem无限适配

    参考文档: http://blog.csdn.net/xwqqq/article/details/54862279 https://github.com/amfe/lib-flexible/tree/ ...

  10. [LeetCode] 529. Minesweeper 扫雷

    Let's play the minesweeper game (Wikipedia, online game)! You are given a 2D char matrix representin ...