EF Code First:实体映射,数据迁移,重构

Posted 渐行渐远....那些错过的青春

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了EF Code First:实体映射,数据迁移,重构相关的知识,希望对你有一定的参考价值。

一、前言

经过EF的《第一篇》,我们已经把数据访问层基本搭建起来了,但并没有涉及实体关系。实体关系对于一个数据库系统来说至关重要,而且EF的各个实体之间的联系,实体之间的协作,联合查询等也都依赖于这些实体关系。

二、实体映射

实体与数据库的映射可以通过DataAnnotation与FluentAPI两种方式来进行映射:

(一) DataAnnotation

DataAnnotation 特性由.NET 3.5中引进,给.NET中的类提供了一种添加验证的方式。DataAnnotation由命名空间System.ComponentModel.DataAnnotations提供。下面列举实体模型中常用的DataAnnotation特性:

  1. KeyAttribute:对应数据库中的主键
  2. RequiredAttribute:对应数据库中字段的数据是否可以为null
  3. MaxLengthAttribute:对应数据库中字符串类型字段的最大长度
  4. MinLengthAttribute:在数据库中无对应,但在代码中字符串最小长度
  5. ConcurrencyCheckAttribute:指定用于开放式并发检查的列的数据类型
  6. TimestampAttribute:将列的数据类型指定为行版本

System.ComponentModel.DataAnnotations命名空间中只定义了部分实体验证的特性,在EntityFramework程序集中定义了更多的数据映射特性:

  1. DatabaseGeneratedAttribute:标记指定实体属性是由数据库生成的,并指定生成策略(None数据库不生成值,Identity当插入行时,数据库生成值,Computed当插入或更新行时,数据库生成值)
  2. ColumnAttribute:指定实体属性在数据库中的列名及数据类型
  3. TableAttribute:指定实体类对应的数据表名
  4. ForeignKeyAttribute:指定导航属性的外键字段
  5. NotMappedAttribute:标记指定实体属性在创建数据库中不创建对应字段
  6. ComplexTypeAttribute:标记指定实体属性是将一个对象作为另一个对象的属性,映射到数据库中则子对象表现为多个属性字段

对于实体关系对应的数据表关系,无非“0:1,1:1,0:N,1:N,N:N”这几种,可以使用导航属性中的数据类型来表示,0…1端使用单实体类型表示,N端使用ICollection<T>集合类型表示。对于单实体端,默认是可为空的,即为0关系,如果要设置为1关系,要使用[Required]标签来进行标记。但对于一对一中的关系主体与依赖对象确无法做更细节的控制。 

(二) Fluent API

使用DataAnnotation非常简单,但对于EntityFramework中的特性,就要在实体类中引入EntityFramework程序集,但实体类最好能是保持与架构无关性的POCO类,才能更具通用性。所以,最好是在数据层中使用FluentAPI在数据层中进行实体类与数据库之间的映射工作。

当然,System.ComponentModel.DataAnnotations命名空间的DataAnnotation在EntityFramework程序集中也有相应的API:

  1. HasKey - KeyAttribute:配置此实体类型的主键属性
  2. IsRequired - RequiredAttribute:将此属性配置为必需属性。用于存储此属性的数据库列将不可以为null
  3. HasMaxLength - MaxLengthAttribute:将属性配置为具有指定的最大长度
  4. IsConcurrencyToken - ConcurrencyCheckAttribute:将属性配置为用作开放式并发标记
  5. IsRowVersion - TimestampAttribute:将属性配置为数据库中的行版本。实际数据类型将因使用的数据库提供程序而异。将属性设置为行版本会自动将属性配置为开放式并发标记。

上面这些API均无需引用EntityFramework,推荐使用DataAnnotation方式来设置映射。

以下API的DataAnnotation特性是在EntityFramework中定义,如果也使用DataAnnotation方式来设置映射,就会给实体类增加额外的第三方程序集的依赖。所以以下API的映射推荐使用FluentAPI的方式来设置映射:

  1. ToTable - TableAttribute:配置此实体类型映射到的表名
  2. HasColumnName - ColumnAttribute:配置用于存储属性的数据库列的名称
  3. HasForeignKey - ForeignKeyAttribute:将关系配置为使用在对象模型中的外键属性。如果未在对象模型中公开外键属性,则使用Map方法
  4. Ignore - NotMappedAttribute:从模型中排队某个属性,使该属性不会映射到数据库
  5. HasRequired:通过此实体类型配置必需关系。除非指定此关系,否则实体类型的实例将无法保存到数据库。数据库中的外键不可为null。
  6. HasOptional:从此实体类型配置可选关系。实体类型的实例将能保存到数据库,而无需指定此关系。数据库中的外键可为null。
  7. HasMany:从此实体类型配置一对多关系。
  8. WithOptional:将关系配置为required:optional。(required:0…1端的1,表示必需,不可为null;optional:0…1端的0,表示可选,可为null。下同
  9. WithOptionalDependent:将关系配置为optional:optional。要配置的实体类型将成为依赖对象,且包含主体的外键。作为关系目标的实体类型将成为关系中的主体。
  10. WithOptionalPrincipal:将关系配置为optional:optional。要配置的实体类型将成为关系中的主体。作为关系目标的实体类型将成为依赖对象,且包含主体的外键。
  11. WithRequired:将关系的指定端配置为必需的,且在关系的另一端有导航属性。
  12. WithRequiredDependent:将关系配置为required:required。要配置的实体类型将成为依赖对象,且包含主体的外键。作为关系目标的实体类型将成为关系中的主体。
  13. WithRequiredPrincipal:将关系配置为required:required。要配置的实体类型将成为关系中的实体。作为关系目标的实体类型将成为依赖对象,且包含主体的外键。
  14. WillCascadeOnDelete:配置是否对关系启用级联删除。
  15. Map:将关系配置为使用未在对象模型中公开的外键属性。可通过指定配置操作来自定义列和表。如果指定了空的配置操作,则约定将生成列名。如果在对象模型中公开了外键属性,则使用 HasForeignKey 方法。并非所有关系都支持在对象模型中公开外键属性。
  16. MapKey:配置外键的列名。
  17. ToTable:配置外键列所在表的名称和架构。

经常用到的DataAnnotation与FluentAPI列举完了,使用上还是遵守这个原则:

如果在System.ComponentModel.DataAnnotations命名空间存在相应的标签,就使用 DataAnnotation 的方式,如果不存在,则使用 FluentAPI 的方式。

(三) 映射代码示例

实体类关系图:

上图是一个以用户信息为中心的实体关系图,关系说明如下:

  1. 一个用户可拥有一个可选的用户扩展信息(1 - 0)
  2. 一个用户扩展信息拥有一个必需的所属用户信息(0 - 1)
  3. 一个用户扩展信息拥有一个用户地址信息(复合类型)
  4. 一个用户可对应多个登录日志信息(1 - N)
  5. 一个登录日志拥有一个必需的所属用户信息(N- 1)
  6. 一个用户可以拥有多个角色(N - N)
  7. 一个角色可以分配给多个用户(N - N)

实体类定义:

用户信息

  1. namespace GMF.Demo.Core.Models  
  2. {  
  3.     /// <summary>  
  4.     ///     实体类——用户信息  
  5.     /// </summary>  
  6.     [Description("用户信息")]  
  7.     public class Member : Entity  
  8.     {  
  9.         public int Id { get; set; }  
  10.  
  11.         [Required]  
  12.         [StringLength(20)]  
  13.         public string UserName { get; set; }  
  14.  
  15.         [Required]  
  16.         [StringLength(32)]  
  17.         public string Password { get; set; }  
  18.  
  19.         [Required]  
  20.         [StringLength(20)]  
  21.         public string NickName { get; set; }  
  22.  
  23.         [Required]  
  24.         [StringLength(50)]  
  25.         public string Email { get; set; }  
  26.  
  27.         /// <summary>  
  28.         /// 获取或设置 用户扩展信息  
  29.         /// </summary>  
  30.         public virtual MemberExtend Extend { get; set; }  
  31.  
  32.         /// <summary>  
  33.         /// 获取或设置 用户拥有的角色信息集合  
  34.         /// </summary>  
  35.         public virtual ICollection<Role> Roles { get; set; }  
  36.  
  37.         /// <summary>  
  38.         /// 获取或设置 用户登录记录集合  
  39.         /// </summary>  
  40.         public virtual ICollection<LoginLog> LoginLogs { get; set; }  
  41.     }  

用户扩展信息

  1. namespace GMF.Demo.Core.Models  
  2. {  
  3.     /// <summary>  
  4.     ///     实体类——用户扩展信息  
  5.     /// </summary>  
  6.     [Description("用户扩展信息")]  
  7.     public class MemberExtend : Entity  
  8.     {  
  9.         /// <summary>  
  10.         /// 初始化一个 用户扩展实体类 的新实例  
  11.         /// </summary>  
  12.         public MemberExtend()  
  13.         {  
  14.             Id = CombHelper.NewComb();  
  15.         }  
  16.  
  17.         public Guid Id { get; set; }  
  18.  
  19.         public string Tel { get; set; }  
  20.  
  21.         public MemberAddress Address { get; set; }  
  22.  
  23.         public virtual Member Member { get; set; }  
  24.     }  

用户地址信息

  1. namespace GMF.Demo.Core.Models  
  2. {  
  3.     /// <summary>  
  4.     /// 用户地址信息  
  5.     /// </summary>  
  6.     public class MemberAddress  
  7.     {  
  8.         [StringLength(10)]  
  9.         public string Province { get; set; }  
  10.  
  11.         [StringLength(20)]  
  12.         public string City { get; set; }  
  13.  
  14.         [StringLength(20)]  
  15.         public string County { get; set; }  
  16.  
  17.         [StringLength(60, MinimumLength = 5)]  
  18.         public string Street { get; set; }  
  19.     }  
  20. }  
  21.  

登录记录信息

  1. namespace GMF.Demo.Core.Models  
  2. {  
  3.     /// <summary>  
  4.     /// 实体类——登录记录信息  
  5.     /// </summary>  
  6.     [Description("登录记录信息")]  
  7.     public class LoginLog : Entity  
  8.     {  
  9.         /// <summary>  
  10.         /// 初始化一个 登录记录实体类 的新实例  
  11.         /// </summary>  
  12.         public LoginLog()  
  13.         {  
  14.             Id = CombHelper.NewComb();  
  15.         }  
  16.  
  17.         public Guid Id { get; set; }  
  18.  
  19.         [Required]  
  20.         [StringLength(15)]  
  21.         public string IpAddress { get; set; }  
  22.  
  23.         /// <summary>  
  24.         /// 获取或设置 所属用户信息  
  25.         /// </summary>  
  26.         public virtual Member Member { get; set; }  
  27.     }  
  28. }  
  29.  

角色信息

  1. namespace GMF.Demo.Core.Models  
  2. {  
  3.     /// <summary>  
  4.     ///     实体类——角色信息  
  5.     /// </summary>  
  6.     [Description("角色信息")]  
  7.     public class Role : Entity  
  8.     {  
  9.         public Role()  
  10.         {  
  11.             Id = CombHelper.NewComb();  
  12.         }  
  13.  
  14.         public Guid Id { get; set; }  
  15.  
  16.         [Required]  
  17.         [StringLength(20)]  
  18.         public string Name { get; set; }  
  19.  
  20.         [StringLength(100)]  
  21.         public string Description { get; set; }  
  22.  
  23.         /// <summary>  
  24.         /// 获取或设置 角色类型  
  25.         /// </summary>  
  26.         public RoleType RoleType { get; set; }  
  27.  
  28.         /// <summary>  
  29.         /// 获取或设置 角色类型的数值表示,用于数据库存储  
  30.         /// </summary>  
  31.         public int RoleTypeNum { get; set; }  
  32.  
  33.         /// <summary>  
  34.         ///     获取或设置 拥有此角色的用户信息集合  
  35.         /// </summary>  
  36.         public virtual ICollection<Member> Members { get; set; }  
  37.     }  
  38. }  
  39.  

角色类型(枚举)

  1. namespace GMF.Demo.Core.Models  
  2. {  
  3.     /// <summary>  
  4.     /// 表示角色类型的枚举  
  5.     /// </summary>  
  6.     [Description("角色类型")]  
  7.     public enum RoleType  
  8.     {  
  9.         /// <summary>  
  10.         /// 用户类型  
  11.         /// </summary>  
  12.         [Description("用户角色")]  
  13.         User = 0,  
  14.  
  15.         /// <summary>  
  16.         /// 管理员类型  
  17.         /// </summary>  
  18.         [Description("管理角色")]  
  19.         Admin = 1  
  20.     }  
  21. }  
  22.  

 

 

实体类映射:

实体类映射中,关系的映射配置在关系的两端都可以配置。例如,用户信息与登录信息的 一对多 关系可以在用户信息端配置:

HasMany(m => m.LoginLogs).WithRequired(n => n.Member);

等效于在登录日志信息端配置:

HasRequired(m => m.Member).WithMany(n => n.LoginLogs);

但是,如果所有的关系映射都在作为主体的用户信息端进行配置,势必造成用户信息端配置的臃肿与职责不明。所以,为了保持各个实体类型的职责单一,实体关系推荐在关系的非主体端进行映射。

用户信息映射类,用户信息是关系的主体,所有的关系都不在此映射类中进行配置

  1. namespace GMF.Demo.Core.Data.Configurations  
  2. {  
  3.     public class MemberConfiguration : EntityTypeConfiguration<Member>  
  4.     {  
  5.     }  

用户扩展信息映射类,配置用户扩展信息与用户信息的 0:1 关系

  1. namespace GMF.Demo.Core.Data.Configurations  
  2. {  
  3.     public class MemberExtendConfiguration : EntityTypeConfiguration<MemberExtend>  
  4.     {  
  5.         public MemberExtendConfiguration()  
  6.         {  
  7.             HasRequired(m => m.Member).WithOptional(n => n.Extend);  
  8.         }  
  9.     }  

用户地址信息映射类,配置用户地址信息的复杂类型映射,复杂类型继承于 ComplexTypeConfiguration<>

  1. namespace GMF.Demo.Core.Data.Configurations  
  2. {  
  3.     public class MemberAddressConfiguration : ComplexTypeConfiguration<MemberAddress>  
  4.     {  
  5.         public MemberAddressConfiguration()  
  6.         {  
  7.             Property(m => m.Province).HasColumnName("Province");  
  8.             Property(m => m.City).HasColumnName("City");  
  9.             Property(m => m.County).HasColumnName("County");  
  10.             Property(m => m.Street).HasColumnName("Street");  
  11.         }  
  12.     }  

登录记录信息映射,配置登录信息与用户信息的 N:1 的关系

  1. namespace GMF.Demo.Core.Data.Configurations  
  2. {  
  3.     public class LoginLogConfiguration : EntityTypeConfiguration<LoginLog>  
  4.     {  
  5.         public LoginLogConfiguration()  
  6.         {  
  7.             HasRequired(m => m.Member).WithMany(n => n.LoginLogs);  
  8.         }  
  9.     }  

角色信息映射,配置角色信息与用户信息的 N:N 的关系

  1. namespace GMF.Demo.Core.Data.Configurations  
  2. {  
  3.     public class RoleConfiguration : EntityTypeConfiguration<Role>  
  4.     {  
  5.         public RoleConfiguration()  
  6.         {  
  7.             HasMany(m => m.Members).WithMany(n => n.Roles);  
  8.         }  
  9.     }  

映射类的应用:

映射类需要在数据访问上下文中进行应用才能生效,只要在DbContext的OnModelCreating方法中进行映射配置添加即可。

  1. protected override void OnModelCreating(DbModelBuilder modelBuilder)  
  2. {  
  3.     //移除一对多的级联删除约定,想要级联删除可以在 EntityTypeConfiguration<TEntity>的实现类中进行控制  
  4.     modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();  
  5.     //多对多启用级联删除约定,不想级联删除可以在删除前判断关联的数据进行拦截  
  6.     //modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();  
  7.  
  8.     modelBuilder.Configurations.Add(new MemberConfiguration());  
  9.     modelBuilder.Configurations.Add(new MemberExtendConfiguration());  
  10.     modelBuilder.Configurations.Add(new MemberAddressConfiguration());  
  11.     modelBuilder.Configurations.Add(new RoleConfiguration());  
  12.     modelBuilder.Configurations.Add(new LoginLogConfiguration());  

三、数据迁移

经过上面的折腾,数据库结构已经大变,项目当然运行不起来了。

根据提示,必须进行迁移来更新数据库结构。EntityFramework的数据迁移通过 NuGet 来进行。打开程序包管理器控制台(Package Manager Console),键入“ get-help EntityFramework”命令,可以获得相关的帮助信息。

若想了解各个子命令的帮助细节,也可键入“get-help 子命令”命令,例如:get-help Enable-Migrations

下面我们来对项目进行数据迁移,在我们的项目中,EntityFramework的依赖止于项目GMF.Demo.Core.Data,项目的数据迁移也是在此项目中进行。迁移步骤如下:

  1. 在“程序包管理器控制台”键入命令:Enable-Migrations -ProjectName GMF.Demo.Core.Data
  2. 添加后,项目中添加了一个名为Migrations的文件夹 添加生成以下代码:
  1. namespace GMF.Demo.Core.Data.Migrations  
  2. {  
  3.     internal sealed class Configuration : DbMigrationsConfiguration<DemoDbContext>  
  4.     {  
  5.         public Configuration()  
  6.         {  
  7.             AutomaticMigrationsEnabled = false;  
  8.         }  
  9.  
  10.         protected override void Seed(DemoDbContext context)  
  11.         {  
  12.             //  This method will be called after migrating to the latest version.  
  13.  
  14.             //  You can use the DbSet<T>.AddOrUpdate() helper extension method   
  15.             //  to avoid creating duplicate seed data. E.g.  
  16.             //  
  17.             //    context.People.AddOrUpdate(  
  18.             //      p => p.FullName,  
  19.             //      new Person { FullName = "Andrew Peters" },  
  20.             //      new Person { FullName = "Brice Lambson" },  
  21.             //      new Person { FullName = "Rowan Miller" }  
  22.             //    );  
  23.             //  
  24.         }  
  25.     }  

方法Seed中可以进行数据迁移后的数据初始化工作,将在每次迁移之后运行。如上代码所示,AddOrUpdate是IDbSet<TEntity>的扩展方法,如果指定条件的数据不存在,则会添加,如果存在,会更新。所以,如果数据是通过此方法来初始化的,在与业务更新之后,再次进行数据迁移后,还是会被还原。

还有一个名为InitialCreate的类,配置生成数据库的细节:

InitialCreate

  1. namespace GMF.Demo.Core.Data.Migrations  
  2. {  
  3.     public partial class InitialCreate : DbMigration  
  4.     {  
  5.         public override void Up()  
  6.         {  
  7.             CreateTable(  
  8.                 "dbo.Roles",  
  9.                 c => new 
  10.                     {  
  11.                         Id = c.Guid(nullable: false),  
  12.                         Name = c.String(nullable: false, maxLength: 20),  
  13.                         Description = c.String(maxLength: 100),  
  14.                         IsDeleted = c.Boolean(nullable: false),  
  15.                         AddDate = c.DateTime(nullable: false),  
  16.                         Timestamp = c.Binary(nullable: false, fixedLength: true, timestamp: true, storeType: "rowversion"),  
  17.                     })  
  18.                 .PrimaryKey(t => t.Id);  
  19.               
  20.             CreateTable(  
  21.                 "dbo.Members",  
  22.                 c => new 
  23.                     {  
  24.                         Id = c.Int(nullable: false, identity: true),  
  25.                         UserName = c.String(nullable: false, maxLength: 20),  
  26.                         Password = c.String(nullable: false, maxLength: 32),  
  27.                         NickName = c.String(nullable: false, maxLength: 20),  
  28.                         Email = c.String(nullable: false, maxLength: 50),  
  29.                         IsDeleted = c.Boolean(nullable: false),  
  30.                         AddDate = c.DateTime(nullable: false),  
  31.                         Timestamp = c.Binary(nullable: false, fixedLength: true, timestamp: true, storeType: "rowversion"),  
  32.                     })  
  33.                 .PrimaryKey(t => t.Id);  
  34.               
  35.             CreateTable(  
  36.                 "dbo.MemberExtends",  
  37.                 c => new 
  38.                     {  
  39.                         Id = c.Guid(nullable: false),  
  40.                         IsDeleted = c.Boolean(nullable: false),  
  41.                         AddDate = c.DateTime(nullable: false),  
  42.                         Timestamp = c.Binary(nullable: false, fixedLength: true, timestamp: true, storeType: "rowversion"),  
  43.                         Member_Id = c.Int(nullable: false),  
  44.                     })  
  45.                 .PrimaryKey(t => t.Id)  
  46.                 .ForeignKey("dbo.Members", t => t.Member_Id)  
  47.                 .Index(t => t.Member_Id);  
  48.               
  49.             CreateTable(  
  50.                 "dbo.LoginLogs",  
  51.                 c => new 
  52.                     {  
  53.                         Id = c.Guid(nullable: false),  
  54.                         IpAddress = c.String(nullable: false, maxLength: 15),  
  55.                         IsDeleted = c.Boolean(nullable: false),  
  56.                         AddDate = c.DateTime(nullable: false),  
  57.                         Timestamp = c.Binary(nullable: false, fixedLength: true, timestamp: true, storeType: "rowversion"),  
  58.                         Member_Id = c.Int(),  
  59.                     })  
  60.                 .PrimaryKey(t => t.Id)  
  61.                 .ForeignKey("dbo.Members", t => t.Member_Id)  
  62.                 .Index(t => t.Member_Id);  
  63.               
  64.             CreateTable(  
  65.                 "dbo.MemberRoles",  
  66.                 c => new 
  67.                     {  
  68.                         Member_Id = c.Int(nullable: false),  
  69.                         Role_Id = c.Guid(nullable: false),  
  70.                     })  
  71.                 .PrimaryKey(t => new { t.Member_Id, t.Role_Id })  
  72.                 .ForeignKey("dbo.Members", t => t.Member_Id, cascadeDelete: true)  
  73.                 .ForeignKey("dbo.Roles", t => t.Role_Id, cascadeDelete: true)  
  74.                 .Index(t => t.Member_Id)  
  75.                 .Index(t => t.Role_Id);  
  76.               
  77.         }  
  78.           
  79.         public override void Down()  
  80.         {  
  81.             DropIndex("dbo.MemberRoles", new[] { "Role_Id" });  
  82.             DropIndex("dbo.MemberRoles", new[] { "Member_Id" });  
  83.             DropIndex("dbo.LoginLogs", new[] { "Member_Id" });  
  84.             DropIndex("dbo.MemberExtends", new[] { "Member_Id" });  
  85.             DropForeignKey("dbo.MemberRoles", "Role_Id", "dbo.Roles");  
  86.             DropForeignKey("dbo.MemberRoles", "Member_Id", "dbo.Members");  
  87.             DropForeignKey("dbo.LoginLogs", "Member_Id", "dbo.Members");  
  88.             DropForeignKey("dbo.MemberExtends", "Member_Id", "dbo.Members");  
  89.             DropTable("dbo.MemberRoles");  
  90.             DropTable("dbo.LoginLogs");  
  91.             DropTable("dbo.MemberExtends");  
  92.             DropTable("dbo.Members");  
  93.             DropTable("dbo.Roles");  
  94.         }  
  95.     }  
  96. }  
  97.  
  1. 执行“Add-Migration FirstMigration”命令,添加一个名为FirstMigration的迁移
  2. 执行“Update-Database”命令,更新数据库架构 如果更新数据库存在冲突而不能执行更新,可以添加 -Force强制执行,例如:“Update-Database -Force”
  3. 设置自动迁移 每次都通过控制台来进行迁移太过麻烦,可以设置为自动迁移。 有以下两个参数可以对自动迁移进行设置: 1. AutomaticMigrationsEnabled:获取或设置 指示迁移数据库时是否可使用自动迁移的值。 2. AutomaticMigrationDataLossAllowed:获取或设置 指示是否可接受自动迁移期间的数据丢失的值。如果设置为false,则将在数据丢失可能作为自动迁移一部分出现时引发异常。 修改迁移的Configuration类如下:
  1. namespace GMF.Demo.Core.Data.Migrations  
  2. {  
  3.     internal sealed class Configuration : DbMigrationsConfiguration<DemoDbContext>  
  4.     {  
  5.         public Configuration()  
  6.         {  
  7.             AutomaticMigrationsEnabled = true;  
  8.             AutomaticMigrationDataLossAllowed = true;  
  9.         }  
  10.  
  11.         protected override void Seed(DemoDbContext context)  
  12.         {  
  13.             List<Member> members = new List<Member>  
  14.             {  
  15.                 new Member { UserName = "admin", Password = "123456", Email = "admin@gmfcn.net", NickName = "管理员" },  
  16.                 new Member { UserName = "gmfcn", Password = "123456", Email = "mf.guo@qq.com", NickName = "郭明锋" }  
  17.             };  
  18.             DbSet<Member> memberSet = context.Set<Member>();  
  19.             memberSet.AddOrUpdate(m => new { m.Id }, members.ToArray());  
  20.         }  
  21.     }  

修改数据库初始化策略如下:

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

四、代码重构

经过上面的演练,我们的项目变成如下图所示:

现在的项目中,数据访问上下文DemoDbContext代码如下所示:

  1. namespace GMF.Demo.Core.Data.Context  
  2. {  
  3.     /// <summary>  
  4.     ///     Demo项目数据访问上下文  
  5.     /// </summary>  
  6.     [Export(typeof(DbContext))]  
  7.     public class DemoDbContext : DbContext  
  8.     {  
  9.         #region 构造函数  
  10.  
  11.         /// <summary>  
  12.         ///     初始化一个 使用连接名称为“default”的数据访问上下文类 的新实例  
  13.         /// </summary>  
  14.         p

    以上是关于EF Code First:实体映射,数据迁移,重构的主要内容,如果未能解决你的问题,请参考以下文章

    EF 中 Code First 的数据迁移以及创建视图

    20.2.翻译系列:EF 6中基于代码的数据库迁移技术EF 6 Code-First系列

    EF Code First Migrations数据库迁移

    EF Code First Migrations数据库迁移

    EF Code First Migrations数据库迁移

    EF Code First Migrations数据库迁移