• 第六节:框架搭建之EF的Fluent Api模式的使用流程


    一. 前言

      沉寂了约一个月的时间,今天用一篇简单的文章重新回归博客,主要来探讨一下Fluent Api模式在实际项目中的使用流程。
    1. Fluent API属于EF CodeFirst模式的一种,EF还有一种模式是DataAnnotations,两种模式各有千秋吧,前面的EF系列已经详细介绍过他们的使用了,本节主要介绍 Fluent API模式在实际框架中的使用流程.
    本节需要用到的技术有:

      ①: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. 业务模拟
      ①. 用户基本信息和角色基本信息,不做关联
      ②. 用户信息增加了或者删除
      ③. 角色信息删除了或者增加

    二. 使用步骤

    1.  新建【Ypf.Service】类库和【Ypf.Test】控制台项目,并分别通过Nuget安装EF程序集。

    2. 在【Ypf.Service】类库中新建“UserInfor”、“RoleInfor”实体类,“UserInforConfig”、“RoleInforConfig”实体类对应的隔离出来的表的配置文件。

    PS:这里为了方便管理,一张表对应一个EF的配置类文件,比全部直接写在 OnModelCreating 方法中更清晰。

    分享实体类代码:

     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     }

    分享表配置文件代码:

     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:配置数据迁移策略固然可以解决该问题,但我们这里用一种比较笨的方法,关闭数据库初始化策略,然后手动配置代码和修改数据库字段进行对应即可。

     分享关闭数据库初始化策略的代码:

     

    手动修改数据库和代码实体中的属性对应后重新运行代码,运行成功。

     

    !

    • 作       者 : Yaopengfei(姚鹏飞)
    • 博客地址 : http://www.cnblogs.com/yaopengfei/
    • 声     明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
    • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
     
  • 相关阅读:
    is 和 == 区别@编码
    python字典
    python的简介
    初始python3
    初始python2
    初始python1
    Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) B2. TV Subscriptions (Hard Version)
    Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) A. Forgetting Things
    2019ICPC区域赛(银川)总结
    Educational Codeforces Round 74 (Rated for Div. 2) D. AB-string
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/9663044.html
Copyright © 2020-2023  润新知