• MVC5+EF6 入门完整教程四


    上篇文章主要讲了如何配置EF, 我们回顾下主要过程:

    创建Data Model à 创建Database Context à创建databaseInitializerà配置entityFramework的context配置节。

    对这个过程还有疑问的可以去上篇再看一下。

    本次我们就主要讲解 (1) EF基本的CRUD (2) 涉及到的常用HtmlHelper

    文章提纲

    概述 & 要点

    理论基础

    详细步骤

    总结

    概述 & 要点

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

    • EF数据模型的CRUD
    • 常用的HtmlHelper
    • Repository Pattern

    理论基础 -- EF 三种编程方式 (略)

    总共有三种方式:

    Database First,Model First和Code First,我们采用的是code first.

    这方面资料很多,我就不重复讲述了, 需要了解这三者差异和应用场景的请自行查阅其他资料。

    理论基础 -- EF CRUD

    针对之前创建的SysUser, SysRole, SysUserRole举一些典型例子,基本的CRUD大家在使用时模仿这些例子就可以了。

    我们要用的数据库示例数据分别如下:    

    SysUser

    SysRole

    SysUserRole

    EF数据查询

    先讲使用频率最高的查询部分。     

    EF数据查询用LINQ实现(LINQ to Entities),通常有表达式和函数式两种方式。建议用函数式方式,比较简单。

    假设我们已经定义好了context

    private AccountContext db = new AccountContext();

    1. [基本查询] 查询所有的SysUser

        var users = from u in db.SysUsers

        select u; //表达式方式

    users = db.SysUsers; //函数式方式

    1. [条件查询] 加入查询条件

        users = from u in db.SysUsers

        where u.UserName == "Tom"

        select u; //表达式方式

        users = db.SysUsers.Where(u => u.UserName == "Tom"); //函数式方式

        NOTE 注意这边等号是C#写法 : " == "

    1. [排序和分页查询]

        users = (from u in db.SysUsers

        orderby u.UserName

        select u).Skip(0).Take(5); //表达式方式

        users = db.SysUsers.OrderBy(u => u.UserName).Skip(0).Take(5); //函数式方式

        NOTE 只有排序了才能分页

    1. [聚合查询]

        //查user总数

        var num = db.SysUsers.Count();

        //查最小ID

        var minId = db.SysUsers.Min(u => u.ID);

        NOTE 聚合查询只能通过函数式查询

    1. [连接查询]

        var users = from ur in db. SysUserRoles

        join u in db. SysUsers

        on ur.SysUserID equals u.ID

      select ur;

    NOTE

    大家注意,连接查询返回的结果还是一个类型为SysUserRoles的集合,只是用

    了内连接进行了的筛选。

    那么问题来了,如果我需要选择一个集合,里面包括多张表,如SysUser里面的UserName和SysRole里面的RoleName怎么办?

    这个是通过navigation property来实现的, 前面新建model的时候提到过,例如SysUser里面的

    public virtual ICollection<SysUserRole> SysUserRoles { getset; }

    但这种做法还是不是太灵活,具体做法我们在下面的详细步骤里面讲。

    EF数据更新

    UPDATE步骤比较清晰,直接看下面代码。

    //数据更新,分三步:找到对象--> 更新对象数据--> 保存更改

    public ActionResult EFUpdateDemo()

    {

    //1.找到对象

    var sysUser = db.SysUsers.FirstOrDefault(u => u.UserName == "Tom");

    //2.更新对象数据

    if (sysUser != null)

    {

    sysUser.UserName = "Tom2";

    }

    //3.保存修改

    db.SaveChanges();

    return View();

    }

    EF数据添加/删除

    与UPDATE类似。

    //数据添加和删除

    public ActionResult EFAddOrDeleteDemo()

    {

    //添加

    //1.创建新的实体

    var newSysUser = new SysUser()

    {

    UserName = "Scott",

    Password = "tiger",

    Email = "Scott@sohu.com"

    };

    //2.增加

    db.SysUsers.Add(newSysUser);

    //3.保存修改

    db.SaveChanges();

     

    //删除

    //1.找到需要删除的对象

    var delSysUser = db.SysUsers.FirstOrDefault(u => u.UserName == "Scott");

    //2.删除

    if (delSysUser!=null)

    {

    db.SysUsers.Remove(delSysUser);

    }

    //3.保存修改

    db.SaveChanges();

    return View("EFQueryDemo");

    }

    详细步骤

    • 查询用户及相应角色的功能
    • 修改用户
    • 增加用户和删除用户

    查询用户及相应的角色

    1. 在Controller中修改Index方法,添加相关View, 显示所有用户
      1. 将model作为参数传过去

      2. Views à Account à Index.cshtml 顶部添加强类型声明,

        @model IEnumerable<MVCDemo.Models.SysUser>

        body中添加个table用来显示数据

        NOTE

        @Html.ActionLink("Details""Details"new { id = item.ID })生成一个相同controller下的路由地址。

        显示结果

         

    2. 增加一个Details方法,添加相关View, 显示相应用户及对应的角色
      1. 将特定的model传过去

         

      2. Views à Account à Index.cshtml 顶部添加强类型声明

        @model MVCDemo.Models.SysUser

        显示数据,注意方框部分如何导航到另外一张表的信息中。

        显示结果

         

    更新用户,增加用户,删除用户

    这三个操作都类似,属于更新的范畴,我们放在一起来讲。

    1. 修改Views à Account à Index.cshtml

      开头增加Create链接。

      table每条记录后面增加Edit,Delete链接。

       

    2. 在Controller中增加相应的方法。

      新建用户:

    //新建用户

    public ActionResult Create()

    {

    return View();

    }

    [HttpPost]

    public ActionResult Create(SysUser sysUser)

    {

    db.SysUsers.Add(sysUser);

    db.SaveChanges();

    return RedirectToAction("Index");

    }

    修改用户:

    //修改用户

    public ActionResult Edit(int id)

    {

    SysUser sysUser = db.SysUsers.Find(id);

    return View(sysUser);

    }

    [HttpPost]

    public ActionResult Edit(SysUser sysUser)

    {

    db.Entry(sysUser).State = EntityState.Modified;

    db.SaveChanges();

    return RedirectToAction("Index");

    }

    删除用户:

    //删除用户

    public ActionResult Delete(int id)

    {

    SysUser sysUser = db.SysUsers.Find(id);

    return View(sysUser);

    }

    [HttpPostActionName("Delete")]

    public ActionResult DeleteConfirmed(int id)

    {

    SysUser sysUser = db.SysUsers.Find(id);

    db.SysUsers.Remove(sysUser);

    db.SaveChanges();

    return RedirectToAction("Index");

    }

    NOTE

    涉及到数据更新的地方都有两个同名的方法重载,一个用来显示[HttpGet],一个用来数据更新[HttpPost]

    1. 在右键方法名,生成相应的View

      每个View的顶部需要添加一个声明

      @model MVCDemo.Models.SysUser

      各个view的body中具体代码:

      Create.cshtml

        <body>

    <div>

    <h2>Create</h2>

    @using (Html.BeginForm())

    {

    <div>

    @Html.LabelFor(model => model.UserName)

    @Html.EditorFor(model => model.UserName)

    </div>

    <div>

    @Html.LabelFor(model => model.Email)

    @Html.EditorFor(model => model.Email)

    </div>

    <div>

    @Html.LabelFor(model => model.Password)

    @Html.PasswordFor(model => model.Password)

    </div>

    <div>

    <input type="submit" value="Create" />

    </div>

    }

    <div>@Html.ActionLink("Back to List","Index")</div>

    </div>

    </body>

    Edit.cshtml

    <body>

    <div>

    <h2>Edit</h2>

    @using (Html.BeginForm())

    {

    @Html.HiddenFor(model => model.ID)

    <div>

    @Html.LabelFor(model => model.UserName)

    @Html.EditorFor(model => model.UserName)

    </div>

    <div>

    @Html.LabelFor(model => model.Email)

    @Html.EditorFor(model => model.Email)

    </div>

    <div>

    @Html.LabelFor(model => model.Password)

    @Html.PasswordFor(model => model.Password)

    </div>

    <div>

    <input type="submit" value="Save" />

    </div>

    }

    <div>@Html.ActionLink("Back to List","Index")</div>

    </div>

    </body>

    Delete.cshtml

    <body>

    <div>

    <h2>Delete</h2>

    <h3>Are you sure you want to delete this? </h3>

    <h4>User</h4>

    <dl>

    <dt>@Html.DisplayNameFor(model => model.UserName)</dt>

    <dd>@Html.DisplayFor(model => model.UserName)</dd>

     

    <dt>@Html.DisplayNameFor(model => model.Email)</dt>

    <dd>@Html.DisplayFor(model => model.Email)</dd>

    </dl>

     

    @using (Html.BeginForm())

    {

    <div>

    <input type="submit" value="Delete" />

    </div>

    }

    <div>

    @Html.ActionLink("Back to List""Index")

    </div>

    </div>

    </body>

    NOTE

    针对上面这些代码,我们提一下其中用到的HtmlHelper, 主要有这么几个:

    DisplayNameFor (model=>model.xxx)à 生成纯文本,显示xxx列名

    DisplayFor (model=>model.xxx)à 生成纯文本,显示xxx列的内容

    LableFor à 生成一个Lable标签

    EditorFor à 生成一个text类型的input

    PasswordFor à 类似于EditorFor, 隐藏文本内容

    ActionLink à 生成一个<a>标签

    BeginForm à 生成一个表单

    NOTE

    HtmlHelper是可以通过View的Html属性调用的方法(@Html.xxx), 可以类比成原来WebForm的服务器端控件, 后续文章会将分成几类, 归类进行介绍,这里先简单提一下做个铺垫。这块最好的学习方法是用浏览器打开相应的页面,View page source,查看生成的相应HTML代码。

    Repository Pattern

    最好再补充下Repository Pattern,为下篇文章重构代码做个铺垫。

    Repository Pattern是一种设计模式,这个概念大家肯定经常听到。

    "企业架构模式" 上的定义:

    Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.

    具体的做法:

    先定义Interface, 通过定义接口确定数据访问类的功能需求, 接着实现该接口。

    以对SysUser这张表的操作为例。

    先建一个文件夹 Repositories, 在文件夹中新建一个接口IsysUserRepository

    我们预先定义几个功能。

    namespace MVCDemo.Repositories

    {

    public interface ISysUserRepository

    {

    //查询所有用户

    IQueryable<SysUser> SelectAll();

    //通过用户名查询用户

    SysUser SelectByName(string userName);

    //添加用户

    void Add(SysUser sysUser);

    //删除用户

    bool Delete(int id);

     

    }

    }

    同样文件夹下新建类,继承接口,实现功能。

    namespace MVCDemo.Repositories

    {

    public class SysUserRepository : ISysUserRepository

    {

    protected AccountContext db = new AccountContext();

    //查询所有用户

    public IQueryable<SysUser> SelectAll()

    {

    return db.SysUsers;

    }

    //通过用户名查询用户

    public SysUser SelectByName(string userName)

    {

    return db.SysUsers.FirstOrDefault(u => u.UserName == userName);

    }

    //添加用户

    public void Add(SysUser sysUser)

    {

    db.SysUsers.Add(sysUser);

    db.SaveChanges();

    }

    //删除用户

    public bool Delete(int id)

    {

    var delSysUser=db.SysUsers.FirstOrDefault(u => u.ID == id);

    if (delSysUser != null)

    {

    db.SysUsers.Remove(delSysUser);

    db.SaveChanges();

    return true;

    }

    else

    {

    return false;

    }

    }

    }

    }

    通过IsysUserRepository接口对象引用SysUserRepository类的实例来调用:

    ISysUserRepository ur=new SysUserRepository();

    var user=ur.xxx;

    怎么样,平时听到的Repository Pattern实现起来就这么简单。

    楼主提示 设计模式都来源于编程实践,只要掌握其中几个重要原则,GOF总结的设计模式都能自己推导出来,就类似于几何中的公理和定理的关系。大家工作中做个有心人,多思考,多总结。

     

    总结

    OK,到此为止,我们对常用的CRUD做了介绍。View, Controller之间都是通过传递Model来交互的。特别要提下下面这张图,通过navigation property实现SysUser à SysUserRole àSysRole 多表间查询。

    当然,这种做法还是有局限性的,后续文章中我们会介绍如何实现类似于之前SQL查询多个表,将多个表的查询结果,例如datatable直接传到view中来显示数据。

    好了,今天就到这里。






  • 相关阅读:
    spark shuffle 机制
    hive explain 源码分析
    前端jQurey
    js-dom操作
    前端JS
    前端CSS
    Redis和MongoDB区别
    MySQL数据库备份
    MySQL索引
    python连接mysql服务端
  • 原文地址:https://www.cnblogs.com/liyanwei/p/894485d408711aa7cdaace136ac464ec.html
Copyright © 2020-2023  润新知