EasyUIEF陆 CodeFirst+Repository+Ninject+MVC4+EasyUI实践(肆)

前言

 

  • 那一篇,我们终于到了讲解Entity
    Framework CodeFirst
    的随时了,首先创造实体对象模型,然后会透过安顿Fluent
    API的法子来对实业对象模型进行一体化的数据库映射操作。
  • 此篇幅中会涉及到部分Entity
    Frame的连锁概念,会提交起首的解释。如若急需详细询问,能够查阅相关的声援文书档案。

 

EF实体对象模型的开创

 

  • EF的实业对象模型大都选用POCO类的主意开创。POCO的完备为Plain_Old_CLR_Object(简单古板CL本田UR-V对象),是指这些并未有从别的类继承,也不曾兑现任何接口的简练对象。EF
    CodeFirst可以选用POCO类成立的实体对象来对数据库进行映射,即我们得以经过编写制定POCO类中的属性和关系POCO类的关系的点子成就对数据库的映照操作。
  • 我们知道数据库的行业内部通过范式来拓展约束,那大家如何通过POCO类的法子来形成对数据库映射以及约束的操作呢?首先大家得把实体对象间的关联创立清楚,实体对象间的关联有三种:壹对壹、一对多、多对多。接下来我们由此完毕示范来演示怎么样创制这个示例。
  1. 打开消除方案的Entities工程,我们把POCO类都成立在此工程下。未有关切过此种类小说的敌人能够在其次篇的末梢下载到消除方案工程文件。成立用户类S_User,与此类关联的对象有S_Role和S_Log,因为3个用户只属于某一个指标,1个用户包罗多条操作日志。因而S_User的代码如下:

      public class S_User

    {
        public S_User(){this.S_Logs = new List<S_Log>();}
        public long ID { get; set; }
        public long RoleID { get; set; }
        public string UserName { get; set; }
        public string UserPwd { get; set; }
        public string IsUse{ get; set; }
        public string Phone{ get; set; }
        public string Email{ get; set; }
        public string Remark { get; set; }
        public virtual S_Role S_Role { get; set; }
        public virtual ICollection<S_Log> S_Logs { get; set; }
    }
    

  2.
接下去是日志类S_Log,与此关联的对象有S_User,即一条日志只属于某四个用户。因此S_Log的代码如下:

  public class S_Log
    {
        public long ID { get; set; }
        public long UserID { get; set; }
        public DateTime OperationDate { get; set; }
        public string  OperationMenu{ get; set; }
        public string  OperationType{ get; set; }
        public string Detail{ get; set; }
        public virtual S_User S_User { get; set; }
    }

  三.
接下去是剧中人物类S_Role,与此关联的对象有S_User和S_Menu,即3个剧中人物能够包蕴三个用户,二个剧中人物用户能够操作多少个菜单页面。

    因此S_Role代码如下:

  public class S_Role
    {
        public S_Role(){ this.S_Users = new List<S_User>();}
        public long ID { get; set; }
        public string RoleName { get; set; }
        public string Remark { get; set; }
        public virtual ICollection<S_User> S_Users { get; set; }
        public virtual ICollection<S_Menu> S_Menus { get; set; }
    }

  4.
接下去是菜单类S_Menu,与此类关联的目的有S_Role,即2个食谱页面能够被四个角色用户操作。可是S_Menu采纳的是树级结构的不二秘籍,

   叁个父级菜单包括多个子菜单,贰个子菜单只属于某一个父级菜单。即子菜单的PID是父级菜单的ID,由此S_Menu的PID因该是S_Menu中ID

  
 的外键,由于超级的父级菜单是没有父级菜单的,所以咱们能够安装PID为可空类型,S_Menu的代码如下:

  public class S_Menu
    {
        public long ID { get; set; }
        public string MenuName { get; set; }
        public string Icon { get; set; }
        public string Link { get; set; }
        public string IsUse { get; set; }
        public int Level { get; set; }
        public int SerialNO { get; set; }
        public Nullable<long> PID { get; set; }
        public string Remark { get; set; }
        public virtual ICollection<S_Role> S_Roles { get; set; }
        public virtual S_Menu Parent { get; set; }
        public virtual ICollection<S_Menu> Children { get; set; }
    }

  五.
接下去是字典类S_TypeInfo,由于尚未与之提到的靶子,由此,大家只需简单定义属性就足以呢。S_TypeInfo的代码如下:

  public class S_TypeInfo
    {
        public long ID { get; set; }
        public string Type { get; set; }
        public string Name { get; set; }
        public string Value { get; set; }
        public string Remark { get; set; }
    }

  6.
注意:一对多涉及中,大家供给对外键的实业举行构造函数进行重载,比如剧中人物中包蕴多少个用户,public
S_Role(){this.S_Users = new

   List<S_User>();}。多对多关系就绝不举行此操作呢。还有一些正是外键必须出示的装置,比如RoleID。因为背后在Fluent
API映射数据时

        ,配置文件中必要用到。

 

EF实体上下文的创建

 

  • 从Nuget上获得EntityFramework,工程选取Concrete,在“程序包管理器控制台”中输入Install-Package
    EntityFramework命令就足以设置了。

  EasyUI 1

  

  • 在Concrete工程中添加EFDbContext类来创设领域实体上下文模型。设置我们的数据库连接名为EFDbContext,修改Web项目下的web.config设置连接名叫EFDbContext,配置好数据库连接字符串后,大家才足以接二连三数据库。在数据库映射的开创方法OnModelCreating中,大家把映射的布署文件放到Mapper工程下,把数据库的开始化操作放到Initializer工程下。EFDbContext代码如下:

      public class EFDbContext : DbContext

    {
        public EFDbContext()
            : base("EFDbContext") { }
    
        public EFDbContext(string nameOrConnectionString)
            : base(nameOrConnectionString) {  }
    
        public DbSet<S_Log> S_Logs { get; set; }
        public DbSet<S_Menu> S_Menus { get; set; }
        public DbSet<S_Role> S_Roles { get; set; }
        public DbSet<S_TypeInfo> S_TypeInfos { get; set; }
        public DbSet<S_User> S_Users { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new S_LogMap());
            modelBuilder.Configurations.Add(new S_MenuMap());
            modelBuilder.Configurations.Add(new S_RoleMap());
            modelBuilder.Configurations.Add(new S_TypeInfoMap());
            modelBuilder.Configurations.Add(new S_UserMap());
    
            modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();  //表中都统一设置禁用一对多级联删除
            modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>(); //表中都统一设置禁用多对多级联删除
    
            base.OnModelCreating(modelBuilder);
        }
    }
    

 

Fluent API配置数据库映射

 

  • 实际上假设不行使数据库配置形式,EntityFramework也足以将实体库映射到数据库文件中,只是可能达不到大家预料的数据库设计的目标,因为EntityFramework会选用暗中认可的数据库映射方式来生成数据库。选取Fluent
    API能够对数据库进行详尽的配置,重要回顾:
  1. 主键的安装
  2. 品质的设置
  3. 表和字段的安装
  4. 关联的设置
  • 在运用Fluent
    API情势安插实体时,实体都两次三番多少个项目为EntityTypeConfiguration的泛型类,唯有继承此类构建的实体才足以在数据库中映射出相应的自律原则。
  • 率先大家来确立一下S_User的映照文件S_UserMap,代码如下:

      public class S_UserMap : EntityTypeConfiguration

    {
        public S_UserMap()
        {
            // Primary Key
            this.HasKey(t => t.ID);
    
            // Properties
            this.Property(t => t.UserName).IsRequired().HasMaxLength(20);
            this.Property(t => t.UserPwd).IsRequired().HasMaxLength(25);
            this.Property(t => t.IsUse).IsRequired().HasMaxLength(2);
            this.Property(t => t.Phone).IsOptional().HasMaxLength(11);
            this.Property(t => t.Email).IsOptional().HasMaxLength(25);
            this.Property(t => t.Remark).IsOptional().HasMaxLength(20);
    
            // Table & Column Mappings
            this.ToTable("S_User");
            this.Property(t => t.ID).HasColumnName("ID").HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
            this.Property(t => t.UserName).HasColumnName("UserName");
            this.Property(t => t.UserPwd).HasColumnName("UserPwd");
            this.Property(t => t.IsUse).HasColumnName("IsUse");
            this.Property(t => t.Phone).HasColumnName("Phone");
            this.Property(t => t.Email).HasColumnName("Email");
            this.Property(t => t.Remark).HasColumnName("Remark");
            this.Property(t => t.RoleID).HasColumnName("RoleID");
    
            // Relationships
            this.HasRequired(t => t.S_Role).WithMany(t => t.S_Users).HasForeignKey(d => d.RoleID);
        }
    }
    

 

  1. S_UserMap继承了EntityTypeConfiguration<S_User>的泛型类
  2. HasKey用来钦定尤其属性为主键
  3. 在Properties设置中,IsRequired用来设定属性为必须字段,不可为空。Has马克斯Length用来设置字段的尺寸。IsOptional用来设定属性为可选字段,能够为空。
  4. ToTable能够用来设置表的名号,HasColumnName用来设定字段的名号。若是你想数据库字段名和实体类中的属性名分歧等,能够在此开始展览安装。HasDatabaseGeneratedOption用来表示字段列是不是为自增加,本示例中,我们的主键采纳的long类型的日期流水码,不要求字段编号。所以设置为none。
  5. 在Relationships中,由于1个用户只属于三个角色,所以RoleID就为S_User对象的外键,配置外键的法子如代码所示。

 

  • 接下去建立S_Role的炫耀文件S_RoleMap,代码如下:

      public class S_RoleMap : EntityTypeConfiguration

    {
        public S_RoleMap()
        { 
              // Primary Key
            this.HasKey(t => t.ID);
    
            // Properties
            this.Property(t => t.RoleName).IsRequired().HasMaxLength(20);
            this.Property(t => t.Remark).IsRequired().HasMaxLength(200);
    
            // Table & Column Mappings
            this.ToTable("S_Role");
            this.Property(t => t.ID).HasColumnName("ID").HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
            this.Property(t => t.RoleName).HasColumnName("RoleName");
            this.Property(t => t.Remark).HasColumnName("Remark");
    
            // Relationships
            this.HasMany(t => t.S_Menus)
            .WithMany(t => t.S_Roles)
            .Map(m =>
            {
                m.ToTable("S_RoleMenu");
                m.MapLeftKey("RoleID");
                m.MapRightKey("MenuID");
            });
        }
    }
    

 

  1. 别的的安装在上头有表达呢,主尽管Relationships,因为那边的S_Role和S_Menu的涉嫌为多对多的涉及,所以会生出一张关系表S_RoleMenu,并且是由RoleID和MenuID联合发出的主键,并且RoleID为S_Menu对象的外键,MenuID为S_Role的外键。

 

  • 接下去建立S_Menu的照耀文件S_MenuMap,代码如下:

      public class S_MenuMap : EntityTypeConfiguration

    {
        public S_MenuMap()
        {
             this.HasKey(t => t.ID);
    
            // Properties
            this.Property(t => t.MenuName).IsRequired().HasMaxLength(20);
            this.Property(t => t.Icon).IsRequired().HasMaxLength(20);
            this.Property(t => t.Link).IsRequired().HasMaxLength(20);
            this.Property(t => t.IsUse).IsOptional().HasMaxLength(2);
            this.Property(t => t.Remark).IsOptional().HasMaxLength(200);
    
            // Table & Column Mappings
            this.ToTable("S_Menu");
            this.Property(t => t.ID).HasColumnName("ID").HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
            this.Property(t => t.MenuName).HasColumnName("MenuName");
            this.Property(t => t.Icon).HasColumnName("Icon");
            this.Property(t => t.Link).HasColumnName("Link");
            this.Property(t => t.IsUse).HasColumnName("IsUse");
            this.Property(t => t.Level).HasColumnName("Level");
            this.Property(t => t.SerialNO).HasColumnName("SerialNO");
            this.Property(t => t.PID).HasColumnName("PID");
            this.Property(t => t.Remark).HasColumnName("Remark");
    
            // Relationships
            this.HasOptional(t => t.Parent)
             .WithMany(t => t.Children)
             .HasForeignKey(d => d.PID);
        }
    }
    

 

  1. 在此提到中,PID为主键ID的外键,并且PID是为可空类型,由其余键的设定形式和RoleID的设定格局一样,只是把HasRequired变成了HasOptional,因为PID能够为空。

 

  • S_LogMap和S_TypeInfoMap就依据上述的方法开创就行吧。
  • 此示例中未有一对1的涉嫌,特此笔者也把壹对一的涉及设定情势以二个示范写出来。

  EasyUI 2

 

开头化数据库

 

  • 因为数据库是经过炫耀自动形成的,所以在数据库发轫化的时候,我们给以为生成的表添加1些暗许数据,比如暗中同意的剧中人物用户admin
  • 在工程Initializer下添加InitializerUserData类和DatabaseInitializer类,InitializerUserData类用来添加私下认可的剧中人物用户。而DatabaseInitializer类负责对数据库的起先化,利用DbContext的Initialize来举行开头化。
  1. InitializerUserData的代码如下:

      public class InitializerUserData : CreateDatabaseIfNotExists

    {
        protected override void Seed(EFDbContext context)
        {
            //添加默认角色
            S_Role role = new S_Role();
            role.ID = NewID.NewComb();
            role.RoleName = "管理员";
            role.Remark = "管理系统所有操作";
    
            //添加默认用户
            long RoleID = role.ID;
            S_User user = new S_User();
            user.ID = NewID.NewComb();
            user.RoleID = RoleID;
            user.UserName ="admin";
            user.UserPwd=DESEncrypt.Encrypt("123");
            user.IsUse="是";
            user.Phone="12345678901";
            user.Email="demo@hotmail.com";
            user.Remark = "系统管理员账户";
            user.S_Role = role;
    
            context.S_Roles.Add(role);
            context.S_Users.Add(user);
            context.SaveChanges();
        }
    }
    

   2. DatabaseInitializer的代码如下:

  public static class DatabaseInitializer
    {
        public static void Initialize()
        {
            Database.SetInitializer(new InitializerUserData());
            using (var db = new EFDbContext())
            {
                db.Database.Initialize(false);
            }
        }
    }

  三.
瞩目:数据的开端化有二种办法,本示例接纳CreateDatabaseIfNotExists,也正是1旦数据库不存在大家就开始展览创办,假使数据仓库储存在,

    大家就只可以通过数量迁移来拓展对数据库的改动操作。

   四. 在web工程的asp.net mvc
项目中的Global.asax添加对Initializer工程的引用,添加对数据库早先化操作的登记。如下展现:  

  public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            DatabaseInitializer.Initialize();
        }
    }
  • 运营WEB工程,大家就足以把实体映射生成数据库,打开数据库管理器查看如下:

  EasyUI 3

 

备注

 

  • 到此,大家完毕了POCO类的建立,以及经过Fluent
    API配置数据库,设置数据库开首化的值,达成了数据库的映射操作。如若要对实体实行改动重新照射到数据库,那么就要动用数据迁移,那几个自家就不多说了。
  • 成就的示范代码,作者会放到网盘,不过当下的代码便是博文提到的,能够点击下载。尽管是温馨搭建的,或然会遇见EntityFramework程序集加载不得法的荒谬。原因是因为本地创设的MVC项目利用的是EntityFramework的5.0本子,而大家透过Nuget获取的是6.0版本,将工程集的EntityFramework五.0本子移除,重新加载六.0的就行啊。