一. 前言html
①:EF的三种模式(四) 之 原生正宗的 CodeFirst模式的默认约定
②:EF的CodeFirst模式经过DataAnnotations修改默认协定
③:EF的CodeFirst模式经过Fluent API修改默认协定
④:EF的CodeFirst模式的四种初始化策略和经过Migration进行数据的迁移数据库
2. 框架模式
这里不采用传统的三层架构(DAL、BLL),而是使用:Ypf.DTO、Ypf.Service、Ypf.IService、Ypf.Utils、Ypf.Web 这种划分模式,本节为了方便测试,仅仅使用 Ypf.Service 和 Ypf.Test(控制台)两个框架进行测试。架构
3. 业务模拟
①. 用户基本信息和角色基本信息,不作关联
②. 用户信息增长了或者删除
③. 角色信息删除了或者增长框架
二. 使用步骤ide
1. 新建【Ypf.Service】类库和【Ypf.Test】控制台项目,并分别经过Nuget安装EF程序集。函数
2. 在【Ypf.Service】类库中新建“UserInfor”、“RoleInfor”实体类,“UserInforConfig”、“RoleInforConfig”实体类对应的隔离出来的表的配置文件。测试
PS:这里为了方便管理,一张表对应一个EF的配置类文件,比所有直接写在 OnModelCreating 方法中更清晰。ui
分享实体类代码:this
1 /// <summary> 2 /// 用户表 3 /// </summary> 4 public class UserInfor 5 { 6 public string id { get; set; } 8 public string userName { get; set; } 10 public int userAge { get; set; } 11 14 } 15 /// <summary> 16 /// 角色信息 17 /// </summary> 18 public class RoleInfor 19 { 20 public string id { get; set; } 22 public string roleName { get; set; } 24 public int roleAge { get; set; } 25 }
分享表配置文件代码:spa
1 /// <summary> 2 /// UserInfor实体对应表的配置 3 /// </summary> 4 class UserInforConfig :EntityTypeConfiguration<UserInfor> 5 { 6 public UserInforConfig() 7 { 8 this.ToTable("T_UserInfor"); 9 this.HasKey<string>(u => u.id).Property(u => u.id).HasColumnType("varchar").HasMaxLength(32); 10 this.Property(u => u.userName).HasColumnType("varchar").HasMaxLength(50); 11 this.Property(u => u.userAge).HasColumnType("int").IsRequired(); 12 } 13 } 14 /// <summary> 15 /// RoleInfor实体对应表的配置 16 /// </summary> 17 class RoleInforConfig : EntityTypeConfiguration<RoleInfor> 18 { 19 public RoleInforConfig() 20 { 21 this.ToTable("T_RoleInfor"); 22 this.HasKey<string>(u => u.id).Property(u => u.id).HasColumnType("varchar").HasMaxLength(32); 23 this.Property(u => u.roleName).HasColumnType("varchar").HasMaxLength(50); 24 this.Property(u => u.roleAge).HasColumnType("int").IsRequired(); 25 } 26 }
3. 在【Ypf.Service】类库中新建EF上下文 “YpfContext”类,使用EF的默认初始化策略(DB不存在则建立,实体不对应则报错) ,而后override OnModelCreating方法,并经过反射一次性加载EF的全部Fluent Api配置,最后声明要映射的实体。
分享EF上下文的代码
public class YpfContext:DbContext { /// <summary> /// 继承父类构造函数,ypfConnectionString表明配置文件中链接字符串的名字 /// </summary> public YpfContext():base("name=ypfConnectionString") { } /// <summary> /// OnModelCreating方法重写,FluentAPI对表的配置都是在该方法中,可是当表数量多的话 /// 该方法内部就会显得特别乱,因此咱们这里采用分离的方式,一张表对应一个配置文件类, /// 最后所有注册到该方法中便可 /// </summary> /// <param name="modelBuilder"></param> protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); //1. 分开注册 //modelBuilder.Configurations.Add(new UserInforConfig()); //modelBuilder.Configurations.Add(new RoleInforConfig()); //2. 一次性加载全部Fluent API的配置 modelBuilder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly()); } public DbSet<UserInfor> UserInfor { get; set; } public DbSet<RoleInfor> RoleInfor { get; set; } }
4. 给【Ypf.Test】配置数据库链接字符串,而且进行一个简单的数据库查询操做,会发如今SQLServer默认目录生成一个名为“FrameFluentApiDB”的数据库,且表、字段对应均正确。
分享数据库链接字符串代码:
1 <connectionStrings> 2 <add name="ypfConnectionString" connectionString="Data Source=localhost;Initial Catalog=FrameFluentApiDB;User ID=sa;Password=123456" providerName="System.Data.SqlClient" /> 3 </connectionStrings>
分享简单的数据库查询代码:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 using (YpfContext db=new YpfContext()) 6 { 7 var list = db.UserInfor.ToList(); 8 9 Console.WriteLine("建立成功"); 10 Console.ReadKey(); 11 } 12 } 13 }
运行后生成的数据库:
5. 给UserInfor实体增长一个“userSex”属性,并在UserInforConfig文件中对该属性进行配置,以下图,再次运行代码,报错,提示上下文发生改变,请走数据迁移。
修改后代码:
报错提示:
PS:配置数据迁移策略当然能够解决该问题,但咱们这里用一种比较笨的方法,关闭数据库初始化策略,而后手动配置代码和修改数据库字段进行对应便可。
分享关闭数据库初始化策略的代码:
手动修改数据库和代码实体中的属性对应后从新运行代码,运行成功。
!