当 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. element ui input 输入时触发事件

    <el-form-item label="客户名" :label-width="labelWidth"> <el-input v-model= ...

  2. spring boot validation参数校验

    对于任何一个应用而言在客户端做的数据有效性验证都不是安全有效的,这时候就要求我们在开发的时候在服务端也对数据的有效性进行验证. Spring Boot自身对数据在服务端的校验有一个比较好的支持,它能将 ...

  3. 刷题记录:[BUUCTF 2018]Online Tool

    目录 刷题记录:[BUUCTF 2018]Online Tool 一.知识点 1.escapeshellarg和escapeshellcmd使用不当导致rce 刷题记录:[BUUCTF 2018]On ...

  4. odoo开发笔记 -- 异常处理in resolve_deps field = model

    场景描述: 更新代码,重启服务服务后,odoo后台报错,提示关键字:in resolve_deps field = model._fields[fname]  KeyError: 'entry_id' ...

  5. 运维笔记--ubuntu安装指定版本的RabbitMQ

    场景描述: 日常开发or生产环境经常会需要安装指定版本的软件,出于和其他软件的配合兼容性,以及稳定性的考虑. 现在我们的需求是安装指定版本的RabbitMQ,版本号: 操作步骤: 注意事项: 异常处理 ...

  6. bat curl 定时请求

    @echo off :loop call:sleep 30 ::调用方法call:sleep [毫秒] (1秒=1000毫秒) curl https://stage.coolfen.com/suppl ...

  7. PAT 甲级 1080 Graduate Admission (30 分) (简单,结构体排序模拟)

    1080 Graduate Admission (30 分)   It is said that in 2011, there are about 100 graduate schools ready ...

  8. CSP2019-终章:afo生活的开始

    出分了...退役了...449...afo了... 曾经立志不少于500的我...竟然450都没上... Orz初中的神仙学弟考了596... 接下来,是一种生活的结束,也是另一种生活的开始... 我 ...

  9. spring mvc 参数类型转换

    实现方式以字符串转Date为例说明: 全局配置 第一种:实现 Converter 接口 实现类: public class StringToDateConveter implements Conver ...

  10. 2017ACM/ICPC广西邀请赛 1004 Covering

    Covering Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...