MVC5+EF6 入门完整教程4 :EF基本的CRUD

概述 & 要点       

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

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

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

总共有三种方式:

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

理论基础 -- EF CRUD

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

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

SysUser

SysRole

SysUserRole

EF数据查询

参见:https://www.cnblogs.com/wfy680/p/15114079.html

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

假设我们已经定义好了context

private AccountContext db = new AccountContext();

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

    //表达式方式

    var users = from u in db.SysUsers

    select u; 

    //函数式方式

    users = db.SysUsers; 

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

    //表达式方式

              users = from u in db.SysUsers where u.UserName == "Tom"

    select u; 

    //函数式方式

    users = db.SysUsers.Where(u => u.UserName == "Tom"); 

   

[排序和分页查询]

    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 只有排序了才能分页

[聚合查询]

    //查user总数

    var num = db.SysUsers.Count();

    //查最小ID

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

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

[连接查询]

    var users = from ur in db. SysUserRoles

    join 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 { get; set; }

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

补充:

内连接inner join:只显示两表id匹配的
左外连接left join:显示join左边的表的所有数据(不管两表是否匹配),对于不匹配的部分都用NULL显示
右外连接right join:与左外连接相反,显示join右边的表的所有数据

 

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");

}

详细步骤

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

一、查询用户及相应的角色

修改Account控制器的 index方法,添加相关View, 显示所有用户

    1. 将Users 这个model作为参数传递给视图【控制器给页面传递参数】
      public ActionResult Index()
      {
           return View(db.Users);   返回视图,给视图传递参数
       }

       

    2. Views ---> Account ---> Index.cshtml 顶部添加强类型声明【页面接收参数】

      @model IEnumerable<MVCDemo.Models.SysUser>

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

        

@model IEnumerable<MVCDemo.Models.User>
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <table>
        <tr>
            <th>@Html.DisplayNameFor(u=>u.UserName)</th>
            <th>@Html.DisplayNameFor(u=>u.Email)</th>
            <th></th>
        </tr>
        @foreach(var item in Model)
        {
            <tr>
                <td>@Html.DisplayFor(m => item.UserName)</td>
                <td>@Html.DisplayFor(m => item.Email)</td>
                <td>@Html.ActionLink("详细信息", "Details", new { id = item.ID })
            </tr>
        }
    </table>
</body>
</html>

 

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

显示结果:

 

 

二、增加一个Details方法,添加相关View, 显示相应用户及对应的角色

    1. 将特定的model传过去
              public ActionResult Details(int id)
              {
                  return View(db.Users.Find(id));   传递1个特定对象
              }

       

    2. Views ---> Account ---> Details.cshtml 顶部添加强类型声明

      @model MVCDemo.Models.SysUser              1个特定对象,不需要IEnumerable

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

      显示结果

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

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

  1. 修改Views---> Account --->Index.cshtml

    开头增加Create链接。

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

     

    @model IEnumerable<MVCDemo.Models.User>
    @{
        Layout = null;
    }
    
    <!DOCTYPE html>
    
    <html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title>Index</title>
    </head>
    <body>
        <p>@Html.ActionLink("添加用户", "Create")</p>
        <table>
            <tr>
                <th>@Html.DisplayNameFor(u=>u.UserName)</th>
                <th>@Html.DisplayNameFor(u=>u.Email)</th>
                <th></th>
            </tr>
            @foreach(var item in Model)
            {
                <tr>
                    <td>@Html.DisplayFor(m => item.UserName)</td>
                    <td>@Html.DisplayFor(m => item.Email)</td>
                    <td>
                        @Html.ActionLink("详细信息", "Details", new { id = item.ID })
                        @Html.ActionLink("编辑", "Edit", new { id = item.ID })
                        @Html.ActionLink("删除", "Delete", new { id = item.ID })
                    </td>
                </tr>
            }
        </table>
    </body>
    </html>

     

     

  2. 在Controller中增加相应的方法。
        //删除用户
        public ActionResult Delete(int id)
        {
            User mUser = db.Users.Find(id);
            return View(mUser);
        }

        [HttpPost, ActionName("Delete")]
        public ActionResult DeleteConfirmed(int id)
        {
            User mUser = db.Users.Find(id);
            db.Users.Remove(mUser);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        //修改用户
        public ActionResult Edit(int id)
        {
            User user = db.Users.Find(id);
            return View(user);
        }

        [HttpPost]
        public ActionResult Edit(User user)
        {
            db.Entry(user).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        public ActionResult Create()  //无model传递给视图
        {
            return View();
        }

        [HttpPost]
        public ActionResult Create(User user)
        {
            db.Users.Add(user);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

 

NOTE

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

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

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

    @model MVCDemo.Models.SysUser

    各个view的body中具体代码:

    Create.cshtml

@model MVCDemo.Models.User

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Create</title>
</head>
<body>
    @using (Html.BeginForm()) 
    {
        @Html.AntiForgeryToken()
        
        <div class="form-horizontal">
            <h4>创建用户</h4>
            <hr />
            @Html.ValidationSummary(true, "", new { @class = "text-danger" })
            <div class="form-group">
                @Html.LabelFor(model => model.UserName, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.UserName, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.UserName, "", new { @class = "text-danger" })
                </div>
            </div>
    
            <div class="form-group">
                @Html.LabelFor(model => model.Email, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.Email, "", new { @class = "text-danger" })
                </div>
            </div>
    
            <div class="form-group">
                @Html.LabelFor(model => model.Password, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Password, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.Password, "", new { @class = "text-danger" })
                </div>
            </div>
    
            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="submit" value="Create" class="btn btn-default" />
                </div>
            </div>
        </div>
    }
    
    <div>
        @Html.ActionLink("Back to List", "Index")
    </div>
</body>
</html>

 

Edit.cshtml

@model MVCDemo.Models.User

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Edit</title>
</head>
<body>
    @using (Html.BeginForm())
    {
        @Html.AntiForgeryToken()
        
        <div class="form-horizontal">
            <h4>User</h4>
            <hr />
            @Html.ValidationSummary(true, "", new { @class = "text-danger" })
            @Html.HiddenFor(model => model.ID)
    
            <div class="form-group">
                @Html.LabelFor(model => model.UserName, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.UserName, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.UserName, "", new { @class = "text-danger" })
                </div>
            </div>
    
            <div class="form-group">
                @Html.LabelFor(model => model.Email, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.Email, "", new { @class = "text-danger" })
                </div>
            </div>
    
            <div class="form-group">
                @Html.LabelFor(model => model.Password, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Password, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.Password, "", new { @class = "text-danger" })
                </div>
            </div>
    
            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="submit" value="Save" class="btn btn-default" />
                </div>
            </div>
        </div>
    }
    
    <div>
        @Html.ActionLink("Back to List", "Index")
    </div>
</body>
</html>

 

Delete.cshtml

@model MVCDemo.Models.User

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Delete</title>
</head>
<body>
    <h3>Are you sure you want to delete this?</h3>
    <div>
        <h4>User</h4>
        <hr />
        <dl class="dl-horizontal">
            <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>
    
            <dt>
                @Html.DisplayNameFor(model => model.Password)
            </dt>
    
            <dd>
                @Html.DisplayFor(model => model.Password)
            </dd>
    
        </dl>
    
        @using (Html.BeginForm()) {
            @Html.AntiForgeryToken()
    
            <div class="form-actions no-color">
                <input type="submit" value="Delete" class="btn btn-default" />  | 
                @Html.ActionLink("Back to List", "Index")
            </div>
        }
    </div>
</body>
</html>

 

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是一种设计模式。

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

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

具体的做法:

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

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

先建文件夹 Repositories

接口IUserRepository

 

namespace MVCDemo.Repositories
{
    public interface IUserRepository
    {
        //查询所有用户
        IQueryable<User> SelectAll();

        //通过用户名查询用户
        User SelectByName(string userName);

        //添加用户
        void Add(User user);

        //删除用户
        bool Delete(int id);
    }
}

 

建类UserRepository ,继承接口,实现功能。

 

namespace MVCDemo.Repositories
{
    public class UserRepository : IUserRepository
    {
        protected EntityContext db = new EntityContext();

        //查询所有用户
        public IQueryable<User> SelectAll()
        {
            return db.Users;
        }

        //通过用户名查询用户
        public User SelectByName(string userName)
        {
            return db.Users.FirstOrDefault(u => u.UserName == userName);
        }

        //添加用户
        public void Add(User sysUser)
        {
            db.Users.Add(sysUser);
            db.SaveChanges();
        }

        //删除用户

        public bool Delete(int id)
        {
            var delUser = db.Users.FirstOrDefault(u => u.ID == id);
            if (delUser != null)
            {
                db.Users.Remove(delUser);
                db.SaveChanges();
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}

 

通过IUserRepository接口对象引用UserRepository类的实例来调用:

IUserRepository ur=new UserRepository();

var user=ur.xxx;

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

 

总结

OK,到此为止,我们对常用的CRUD(增删改查)做了介绍。View, Controller之间都是通过传递Model来交互的。特别要提下下面这张图,通过navigation property实现User ---> UserRole ---> Role 多表间查询。

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

        <dl class="dl-horizontal">
            <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>
            <dt>@Html.DisplayNameFor(model => model.Password) </dt>
            <dd>@Html.DisplayFor(model => model.Password)</dd><dt>@Html.DisplayNameFor(model=>model.UserRoles)</dt>
            <dd>
                <table>
                    <tr>
                        <th>规则名称</th>
                        <th>规则描述</th>
                    </tr>
                    @foreach(var item in Model.UserRoles)
                    {
                        <tr>
                            <td>@Html.DisplayFor(modelItem=> item.Role.RoleName)</td>
                            <td>@Html.DisplayFor(modelItem => item.Role.RoleDesc)</td>
                        </tr>
                    }
                </table>
            </dd>
        </dl>

 

posted @ 2020-02-04 08:23  清语堂  阅读(443)  评论(0编辑  收藏  举报