Laravel 6.5.1 发布了,这是一个补丁版本,包含一些更改和修复。

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

以下由中文社区翻译,能力有限,如有翻译错误,欢迎加入
QQ 群指正!

除非条件为假,否则 @includeUnless 指令包括模板:

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

Nim 团队很高兴为大家带来 1.0.4 版本发布的消息, 这是我们在 Nim 1.0.0
之后发布的第二个补丁版本。

{{-- Instead of this --}}
@includeWhen(! $headless, 'dashboard/partials/nav')

{{-- You can do this --}}
@includeUnless($headless, 'dashboard/partials/nav')

澳门新葡萄京所有网站 1

想要了解更多关于 1.0.0 版本的细节,可以查看我们两个月前
版本发布说明。

此外,新版本通过传递计数值并将默认值更新为等于 1 来修复 PhpRedis spop
实现。 

澳门新葡萄京所有网站 2

距离前一个版本的发布尽管只是过去了一个月的时间,
但这次的版本已经包含了超过 70
次新的提交,
新修复了 20 个问题, 让我们的 1.0 版本变成了更好的样子。

澳门新葡萄京所有网站,Model::isDirty() 检查也获得了针对集合和对象强制转换的修复程序。

 

安装 1.0.4

如果你已经用 choosenim 安装了之前版本的 Nim , 升级到 Nim 的 1.0.4
版本会非常简单:

$ choosenim update stable

如果你还没有安装 choosenim , 你可以通过
这些说明 来下载和安装
choosenim, 当然你也可以按照我们的
安装 页面直接安装。

6.5.1 版本更新列表:

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

更新日志

你可以 在我们的 GitHub
仓库中
查阅此版本的变更日志以及 Nim 的其余源码。


附《更新日志》

Added

  • 添加了 includeUnless 指令
    (#30538)

Member 实体类定义如下:

语言层面的变更

  • 模仿早期版本的 Nim ,在运行时取消了对无符号整数转换的检查。
    文档中已针对这一改进做出了说明。查看
    https://github.com/nim-lang/RFCs/issues/175
    了解更多细节 (#12688)
  • 添加了 or detectOs(Manjaro),这样当检测到系统为 Manjaro
    时,调用原生的包管理器会使用 pacman 进行包管理
    (#12587)
  • --os:ios 编译指令现在也代表了 macosx
    (#12585)
  • 导出了 nim.cfg 解析器,现在其他工具也可以调用 readConfigFile
    (#12602)

Fixed

  • 修复了 PhpRedisConnection::spop() 方法中 $count 的默认值
    (#30546)
  • 修复了多模式 Postgres 的破坏兼容性
    (#30562, 6460d2b)
  • 修复 Model::isDirty()
    (#30565)
  • 修复 MailgunTransport::send() 中的 bcc
    (#30569)

[csharp] view
plain
copy
print?

BUG 修复

  • 修复了 “在 OSX 上多次调用后,gorgeEx() 失败”的问题
    (#12337)
  • 优化和加强了 posix 模块
    (#10723)
  • 修复了 “Nim 的语法检查 允许使用 gorgeEx(),但不允许 writeFile()
    的问题,现在这两个都被提示 don’t run staticExec for ‘nim suggest
    了 (#12491)
  • 修复了 “一个算数的低级错误: -3 mod 7 == 3”
    (#12514)
  • 修复了 “后端集成文档中 c2nim 链接失效”
    的问题(#12537)
  • 修复了 “‎具有默认值的泛型参数会导致不正确的泛型类型解析‎” 的问题
    (#12528)
  • 修复了 “再次出现的问题: compiler/vmgen.nim(354, 20) false leaking
    temporary 10 slotTempInt [AssertionError]
    (#12547)
  • 修复了 “Windows 上的 64 位(只有在 64 位上有问题) nim 编译/链接断开”
    (#12536)
  • 修复了 “除了最新的 devel 版本No =destroy for elements of closure
    environments other than for latest devel –gc:destructors”
    (#12577)
  • 修复了 “[1.0.0] 无法使用 –cpu:avr 进行编译”
    (#12395)
  • 修复了 “使用无效的对象变体会导致编译器崩溃”
    (#12379)
  • 修复了 “import 之前写的编译指示会被静默忽略”
    (#5050)
  • 修复了 “ strformat + asyncdispatch + const 同时使用会报错” 的问题
    (#12612)
  • 修复了 “--nimblePath 是附加的,需要一个无痛的解决方案”
    (#12601)
  • 修复了 “nim.cfg 中 –define:FOO:VAL 的语法没有文档或者缺失”
    (#12367)
  • 修复了 “使用宏生成的 vm 字符串无法正常使用”
    (#12670)
  • 修复了 “staticRead() 引入的静态文件变更时,会强制触发重新编译。”
    (#12663)
  • 修复了终止处理程序中调用 throw 引发的崩溃
    (#12572)
  • 修复了用于 具有字符串字段的对象 的 newLit
    (#12542)

Changed

  • 从 Container 包中删除 illuminate/support 依赖项
    (#30518, #30528)

更新说明:

(文/开源中国)    

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

文档更新

  • 给 Math 模块添加了文档
    (#12460)
  • 修复了许多无效的链接,尽量将链接替换为了链接到文档内部
    (#12463)
  • sequtils:在示例中替换掉了已经遗弃的 ‘random’ 用法
    (#12515)
  • 给整型添加了文档
    (#12513)
  • 修复了代码风格的错误
    (#12545)
  • 修正文档和注释中的几个错误
    (#12553)
  • 添加文档以更好地区分 getProjectPath, getCurrentDir
    currentSourcePath (#12565)
  • doc/tut3.rst: 修复了介绍中的错别字
    (#12607)
  • 添加了指向 packagingdistro 页面的链接
    (#12603)
  • 修复了 $*(dt: DateTime) 的说明
    (#12660)
  • 在 manual.rst 中对 experimental / parallel 加入了示例以明确区别
    (#12472)
  • 修复手册中错误的章节层级关系
    (#12724)

(文/开源中国)    

澳门新葡萄京所有网站 3

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 实体类定义如下:

[csharp] view
plain
copy
print?

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

澳门新葡萄京所有网站 4

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 类定义如下:

[csharp] view
plain
copy
print?

  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.   
  10.             // Properties  
  11.             this.Property(t => t.Id)  
  12.                 .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);  
  13.   
  14.             this.Property(t => t.Name)  
  15.                 .IsRequired()  
  16.                 .HasMaxLength(10);  
  17.   
  18.             this.Property(t => t.Email)  
  19.                 .IsRequired()  
  20.                 .HasMaxLength(200);  
  21.   
  22.             // Table & Column Mappings  
  23.             this.ToTable(“Member”);  
  24.             this.Property(t => t.Id).HasColumnName(“Id”);  
  25.             this.Property(t => t.Name).HasColumnName(“Name”);  
  26.             this.Property(t => t.Email).HasColumnName(“Email”);  
  27.         }  
  28.     }  
  29. }  

澳门新葡萄京所有网站 5

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 类定义如下:

[csharp] view
plain
copy
print?

  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.   
  10.             // Properties  
  11.             this.Property(t => t.Message)  
  12.                 .IsRequired()  
  13.                 .HasMaxLength(200);  
  14.   
  15.             // Table & Column Mappings  
  16.             this.ToTable(“Guestbook”);  
  17.             this.Property(t => t.Id).HasColumnName(“Id”);  
  18.             this.Property(t => t.Message).HasColumnName(“Message”);  
  19.             this.Property(t => t.CreatedOn).HasColumnName(“CreatedOn”);  
  20.             this.Property(t => t.MemberId).HasColumnName(“MemberId”);  
  21.   
  22.             // Relationships  
  23.             this.HasRequired(t => t.Member)  
  24.                 .WithMany(t => t.Guestbooks)  
  25.                 .HasForeignKey(d => d.MemberId);  
  26.   
  27.         }  
  28.     }  
  29. }  

澳门新葡萄京所有网站 6

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 类定义如下:

[csharp] view
plain
copy
print?

  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.   
  10.         public CodeFirstDemoContext()  
  11.             : base(“Name=CodeFirstDemoContext”)  
  12.         {  
  13.         }  
  14.   
  15.         public DbSet<Guestbook> Guestbooks { get; set; }  
  16.         public DbSet<Member> Members { get; set; }  
  17.   
  18.         protected override void OnModelCreating(DbModelBuilder modelBuilder)  
  19.         {  
  20.             modelBuilder.Configurations.Add(new GuestbookMap());  
  21.             modelBuilder.Configurations.Add(new MemberMap());  
  22.         }  
  23.     }  
  24. }  

澳门新葡萄京所有网站 7

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 文件夹结构下

澳门新葡萄京所有网站 8

 

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

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

[csharp] view
plain
copy
print?

  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>  

澳门新葡萄京所有网站 9

<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

[csharp] view
plain
copy
print?

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

澳门新葡萄京所有网站 10

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
的系统数据表,如下图所示:

澳门新葡萄京所有网站 11

 

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

澳门新葡萄京所有网站 12

 

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

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

启用数据库迁移

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

澳门新葡萄京所有网站 13

澳门新葡萄京所有网站 14

 

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

澳门新葡萄京所有网站 15

 

1.      201309120825043_InitialCreate.cs

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

[csharp] view
plain
copy
print?

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

澳门新葡萄京所有网站 16

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 自动迁移数据库。

[csharp] view
plain
copy
print?

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

澳门新葡萄京所有网站 17

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
属性。

[csharp] view
plain
copy
print?

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

澳门新葡萄京所有网站 18

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,则可以输入以下指令:

澳门新葡萄京所有网站 19

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

澳门新葡萄京所有网站 20

 

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

[csharp] view
plain
copy
print?

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

澳门新葡萄京所有网站 21

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
数据表中输入几条数据,以确认待会儿数据库迁移(升级)之后数据是否消失,如图:

澳门新葡萄京所有网站 22

 

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

澳门新葡萄京所有网站 23

 

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

澳门新葡萄京所有网站 24

 

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

[csharp] view
plain
copy
print?

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

澳门新葡萄京所有网站 25

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

[csharp] view
plain
copy
print?

  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.   
  10.             // Properties  
  11.             this.Property(t => t.Id)  
  12.                 .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);  
  13.   
  14.             this.Property(t => t.Name)  
  15.                 .IsRequired()  
  16.                 .HasMaxLength(10);  
  17.   
  18.             this.Property(t => t.Email)  
  19.                 .IsRequired()  
  20.                 .HasMaxLength(200);  
  21.   
  22.             this.Property(t => t.CreatedOn)  
  23.                 .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);  
  24.   
  25.             // Table & Column Mappings  
  26.             this.ToTable(“Member”);  
  27.             this.Property(t => t.Id).HasColumnName(“Id”);  
  28.             this.Property(t => t.Name).HasColumnName(“Name”);  
  29.             this.Property(t => t.Email).HasColumnName(“Email”);  
  30.         }  
  31.     }  
  32. }  

澳门新葡萄京所有网站 26

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

澳门新葡萄京所有网站 27

 

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

[csharp] view
plain
copy
print?

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

澳门新葡萄京所有网站 28

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新增一条版本记录,如下图:

澳门新葡萄京所有网站 29

 

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

[csharp] view
plain
copy
print?

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

澳门新葡萄京所有网站 30

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() 默认值,如下图:

澳门新葡萄京所有网站 31

 

TIPS

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

 

自动数据库迁移

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

[csharp] view
plain
copy
print?

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

澳门新葡萄京所有网站 32

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

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

[csharp] view
plain
copy
print?

  1. AutomaticMigrationsEnabled = true;  

澳门新葡萄京所有网站 33

AutomaticMigrationsEnabled = true;

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

澳门新葡萄京所有网站 34

 

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

 

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

[csharp] view
plain
copy
print?

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

澳门新葡萄京所有网站 35

Database.SetInitializer<CodeFirstDemoContext>(null);

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