MVC5+EF6 入门完整教程3 :EF完整开发流程

 

概述 & 要点

下面是本文要点,正文部分会有详细介绍。

  • EF架构图
  • 新建基于EF的Data Model的约定
  • 关于ORM的重要概念,和传统方式开发的区别
  • EF开发的整体过程

 

一、根目录下新建一个 ViewModels文件夹

Models文件夹存放对应于数据库表的实体;

View显示的数据和Models中实体模型不一定能对应上, 因此需要建立一个文件夹ViewModels专门存放View使用的自定义数据模型;

 

二、根目录下新建一个DAL 文件夹

           DAL 存放数据访问相关类。

            NOTE 本文中放AccountContext.cs, AccountInitializer.cs

 

三、创建相关类(Data Model)

针对用户建立三个相关的类:

SysUser, SysRole, SysUserRole

这是用户权限管理RBAC (Role – Based Access Control)的一个典型模型, 更复杂的模型都可以在这个基础上进行扩展。

OK,下面我们就开始新建这个模型。

我们先去网上找个大致的关系图做参考,打开百度,输入 user role , 搜索图片。

挑一个类似的做参考。

 

NOTE 权限相关是系统管理范畴的,不涉及具体业务,我起名字的时候都加了Sys前缀,这样和业务区隔开来。

参考上面这个图建立 Data Model

SysUser Entity

SysRole Entity

SysUserRole Entity

对于上面几个类的约定和说明:

  1. EF生成数据库的主键:约定:EF默认会将IDclassnameID生成为主键 MSDN建议保持风格的一致性, 都用ID或classnameID, 我们这里都用ID)
  2. EF生成数据库的外键 :  约定:<navigation property name><primary key property name>这种形式的会成为外键

    例如外键 SysUserID = SysUser(navigation property) + ID(SysUser的主键)

  3. 定义为virtual的几个属性是 navigation 属性(virtual非必须, 只是惯例用法, 后面文章将会讲解用virtual的好处).

    navigation 属性保存着其他的关联entity(entities)

    示例中, SysUser和SysUserRole是一对多的关系, SysRole和SysUserRole也是一对多的关系.

    如果是 "多", 属性类型就必须是list( 这里用的是Icollection )

四、创建 Database Context

前置条件:安装EF

在程序包管理器控制台输入 install-package entityframework

 

去MSDN上查看下EF的架构图:http://msdn.microsoft.com/en-us/data/aa937709

从上图可以看出,EF框架在底层是通过调用ADO.NET来实现数据库操作的。

多转一道弯,性能和灵活性肯定会受到影响,所以本系列文章结束后同样也会给出MVC+ADO.NET的方案,大家可以根据需要选择。

NOTE

微软官方推出的ORM框架主要有Linq to SQLEntity Framework.

EF是目前最新的,也是推荐配合MVC使用的框架。

实际操作前再补充一些重要概念:

如果不用ORM框架,我们一般这样来使用ADO.NET进行数据库开发:

  1. 将ADO.NET对数据库的操作封装到一个类里SqlHelper中
  2. 在DAL层调用SqlHelper
  3. 其他层再调用DAL进行数据库操作

使用ORM之后,以前面的SysUser为例:

O(Object) ---> 程序中的类 SysUser, 就是对象

R (Relation) ---> 数据库中的表

M(Mapping) ---> O和R的映射关系

ORM对传统方式的改进:

充当桥梁,实现了关系数据和对象数据的映射,通过映射自动产生SQL语句

对常用的操作,节省了写SQL语句的步骤。

 

创建类 AccountContext.cs , 继承System.Data.Entity.DbContext, 这个类完成EF的功能。

主要做下面三件事:

  1. 为每个entity set创建一个DbSet

    在EF中,通常情况下一个entity set对应数据库中的一张表,一个entity对应表中的一行。

  2. 指定一个连接字符串

    构造函数中的 base("AccountContext") 。

    默认情况下和类名一样,即AccountContext,我们显式的给他指定出来。

  3. 指定单数形式的表名

    >();

    默认情况下会生成复数形式的表,如SysUsers

    NOTE 表名用单复数形式看各自的习惯,没有明确的规定。有的公司表名全用单数,有的公司根据表的意思,有单数也有复数。

    public class AccountContext:DbContext
    {
        public AccountContext():base("AccountContext")
        {
        }
        public DbSet<SysUser> SysUsers { get; set; }
        public DbSet<SysRole> SysRoles { get; set; }
        public DbSet<SysUserRole> SysUserRoles { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }
    }

 

五、在web.config配置连接字符串

如下图,贴着appSettings配置节上面添加。注意要web.config中要加上红字部分,不然会出错。

  <connectionStrings>
    <add name="AccountContext" connectionString="Data Source=.;database=MvcDemo;uid=sa;pwd=6617saSA;
AttachDBFilename=|DataDirectory|\MvcDemo.mdf;
" providerName="System.Data.SqlClient"/> </connectionStrings>

 或先建立数据库MVC_Demo

  <connectionStrings>
    <add name="DbConStr" connectionString="Data Source= WFYWORK\SQLEXPRESS ;Initial Catalog=MVC_Demo;Persist Security Info=True;User ID=sa;Password=6617saSA"
              providerName="System.Data.SqlClient" />
  </connectionStrings>

 

NOTE AttachDBFilename=|DataDirectory|\MVCDemo.mdf设定了数据库文件的存放位置:在项目根目录的App_Data文件夹下

 

六、创建AccountInitializer, 使用EF初始化数据库,插入示例数据

Entity Framework 数据库初始化的三种方法

1、CreateDatabaseIfNotExists:在没有数据库时创建一个,这是默认行为。

2、DropCreateDatabaseIfModelChanges:模型改变时,自动重新创建一个新的数据库,就可以用这个方法。这在开发过程中非常有用。

3、DropCreateDatabaseAlways:每次运行时都重新生成数据库。

目前在开发阶段,不用管数据丢失的问题,直接drop and re-create比较方便。

等系列文章结束后会讲解生产环境中如何不丢失数据修改schema

6.1、新建一个类继承

public class  AccountInitializer: DropCreateDatabaseIfModelChanges<AccountContext>

{

}

 

6.2、重写Seed方法,插入数据

    public class AccountInitializer : DropCreateDatabaseIfModelChanges<AccountContext>
    {
        protected override void Seed(AccountContext context)
        {
            var sysUsers = new List<SysUser>
            {
                new SysUser { UserName="吴先生",Password="123456" },
                new SysUser { UserName="徐先生",Password="123456" }
            };

            sysUsers.ForEach(s => context.SysUsers.Add(s));
            context.SaveChanges();

            var sysRoles = new List<SysRole>
            {
                new Models.SysRole {RoleName="Administrators",RoleDesc="Administrators具有系统管理的所有权限" },
                new Models.SysRole {RoleName="General Users",RoleDesc="General Users 可以访问已经授权的数据" }
            };

            sysRoles.ForEach(s => context.SysRoles.Add(s));
            context.SaveChanges();

            base.Seed(context);
        }
    }

 

6.3、运行

在Global.asax里执行

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

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

    Database.SetInitializer<AccountContext>(new AccountInitializer ()); 
}

或在EF上下文的OnModelCreating里执行

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
  
Database.SetInitializer<AccountContext>(new AccountInitializer ());
base.OnModelCreating(modelBuilder);
}

===================================  下面的方法没有测试  =================================== 

修改web.config, 通知EF使用我们刚刚写好的AccountInitializer类。

找到entityFramework配置节,添加下图方框处内容。

context 配置节中, type 的值对应 (AccountContext的完整描述,程序集

databaseInitializer 配置节中 , type 的值对应 (initializer class 的完整描述,程序集

NOTE : 如果你不想EF使用某个context, 可以将下面方框处设置为true.

 

====================================================================== 

七、完成数据库查询验证

Database.SetInitializer(new AccountInitializer ()); 仅仅是设置数据库初始化器,不建立数据库。

 

 ***********************************************************************************************************************

现在EF一切就绪.

运行程序,当第一次连接数据库时,EF比较model(AccountContext和entity classes) 和database. 如果两边不一致,程序将会drop and re-create数据库。

因为目前我们还没有连接数据库的操作,所以EF还没发挥作用。

现在我们完成前面的Login功能。

添加Email字段:

在public class User里面添加个Email字段。

在AccountInitializer.cs--->Seed函数里增加这个字段

namespace MVCDemo.Models
{
    public class User
    {
        public int ID { get; set; }
        public string UserName { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public virtual ICollection<UserRole> UserRoles { get; set; }
    }
}
var Users = new List<User>
            {
                new User { UserName="张三", Email="张三@139.com",Password="123456" },
                new User { UserName="李四",Email="李四@139.com",Password="123456" }
            };

 

NOTE 添加一个Email是因为之前的登录页面填入的是Email值,后面将会输入Email和Password到数据库中进行比对。

在AccountController.cs实例化一个database context 对象:DemoContext db = new DemoContext();

        [HttpPost]
        public ActionResult Login(FormCollection fc)
        {
            string email = fc["inputEmail3"];
            string password= fc["inputPassword3"];
            var user = db.Users.Where(a => a.Email == email && a.Password == password);
            if(user.Count()>0)
            {
                ViewBag.LoginState = email + "登录后...";
            }
            else
            {
                ViewBag.LoginState = email + "用户不存在...";
            }     
            return View();
        }

 

 

运行Login.cshtml页面,输入正确的和错误的登录信息验证下。

另外再检查一下数据库部分是否符合我们的预期:

  1. 打开数据库,发现MVCDemo这个数据库已经新建,示例数据已经插入。
  2. 打开项目的App_Data 文件夹,发现数据库文件已经存在。【在没有按照数据库,使用VS自带的数据库的情况下

     

总结

OK,到此为止,我们搭建好了EF框架,进行了数据库的初始化,查询了一条用户信息。

需要说明的是,现在的登录功能还比较简陋,不是真正的登录功能(例如输入项还缺少验证,密码还没有加盐),只是为了说明EF的用法。根据系列文章讲述知识点的需要,最终会实现完整功能。

最后再回顾下本篇文章的重点:掌握使用EF开发的整个过程

创建Data Model---> 创建Database Context ---> 创建databaseInitializer ---> 配置entityFramework的context配置节

希望大家能清晰的了解上面整个过程,理解每一个过程的作用。

 

posted @ 2020-02-03 11:20  清语堂  阅读(2310)  评论(0编辑  收藏  举报