MVC5+EF6 入门完整教程4 :EF基本的CRUD
上篇文章主要讲了如何配置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();
[基本查询] 查询所有的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"); //函数式方式
NOTE 注意这边等号是C#写法 : " == "
[排序和分页查询]
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 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 { 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");
}
详细步骤
- 查询用户及相应角色的功能
- 修改用户
- 增加用户和删除用户
查询用户及相应的角色
在Controller中修改Index方法,添加相关View, 显示所有用户
- 将model作为参数传过去 控制器方法传参数
- Views ---> Account ---> Index.cshtml 顶部添加强类型声明,页面处理显示参数
@model IEnumerable<MVCDemo.Models.SysUser>
body中添加个table用来显示数据
NOTE
@Html.ActionLink("Details", "Details", new { id = item.ID })生成一个相同controller下的路由地址。
显示结果
增加一个Details方法,添加相关View, 显示相应用户及对应的角色
- 将特定的model传过去
- Views ---> Account ---> Details.cshtml 顶部添加强类型声明
@model MVCDemo.Models.SysUser
显示数据,注意方框部分如何导航到另外一张表的信息中。
显示结果
更新用户,增加用户,删除用户
这三个操作都类似,属于更新的范畴,我们放在一起来讲。
- 修改Views---> Account --->Index.cshtml
开头增加Create链接。
table每条记录后面增加Edit,Delete链接。
@model IEnumerable<SportsStore.WebUI.SysUser>
@{
Layout = null;
}<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<p>@Html.ActionLink("Create New","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","Details",new { id = item.ID } )
@Html.ActionLink("Edit", "Edit", new { id = item.ID })
@Html.ActionLink("Delete", "Delete", new { id = item.ID })
</td>
</tr>
}
</table>
</body>
</html> - 在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);
}
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
SysUser sysUser = db.SysUsers.Find(id);
db.SysUsers.Remove(sysUser);
db.SaveChanges();
return RedirectToAction("Index");
}
NOTE
涉及到数据更新的地方都有两个同名的方法重载,一个用来显示[HttpGet],一个用来数据更新[HttpPost]
- 在右键方法名,生成相应的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>
>
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是一种设计模式。
"企业架构模式" 上的定义:
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中来显示数据。
MVC5+EF6 入门完整教程4 :EF基本的CRUD的更多相关文章
- MVC5+EF6 入门完整教程
MVC5+EF6 入门完整教程11--细说MVC中仓储模式的应用 MVC5+EF6 入门完整教程10:多对多关联表更新&使用原生SQL@20150521 MVC5+EF6 入门完整教程9:多表 ...
- MVC5+EF6 入门完整教程九
前一阵子临时有事,这篇文章发布间隔比较长,我们先回顾下之前的内容,每篇文章用一句话总结重点. 文章一 MVC核心概念简介,一个基本MVC项目结构 文章二 通过开发一个最基本的登录界面,介绍了如何从Co ...
- MVC5+EF6 入门完整教程13 -- 动态生成多级菜单
稍微有一定复杂性的系统,多级菜单都是一个必备组件. 本篇专题讲述如何生成动态多级菜单的通用做法. 我们不用任何第三方的组件,完全自己构建灵活通用的多级菜单. 需要达成的效果:容易复用,可以根据mode ...
- MVC5+EF6 入门完整教程11--细说MVC中仓储模式的应用
摘要: 第一阶段1~10篇已经覆盖了MVC开发必要的基本知识. 第二阶段11-20篇将会侧重于专题的讲解,一篇文章解决一个实际问题. 根据园友的反馈, 本篇文章将会先对呼声最高的仓储模式进行讲解. 文 ...
- MVC5 + EF6 入门完整教程二
从前端的UI开始 MVC分离的比较好,开发顺序没有特别要求,先开发哪一部分都可以,这次我们主要讲解前端UI的部分. ASP.NET MVC抛弃了WebForm的一些特有的习惯,例如服务器端控件,Vie ...
- MVC5+EF6 入门完整教程12--灵活控制Action权限
大家久等了. 本篇专题主要讲述MVC中的权限方案. 权限控制是每个系统都必须解决的问题,也是园子里讨论最多的专题之一. 前面的系列文章中我们用到了 SysUser, SysRole, SysUserR ...
- MVC5+EF6 入门完整教程 总目录
本系列文章会从一个主干开始,逐渐深入,初步规划30篇.初级10篇,中级10篇,综合项目实战10篇 初级10篇 MVC5+EF6 入门完整教程10:多对多关联表更新&使用原生SQL@201505 ...
- MVC5 + EF6 入门完整教程1
https://www.cnblogs.com/miro/p/4030622.html 第0课 从0开始 ASP.NET MVC开发模式和传统的WebForm开发模式相比,增加了很多"约定& ...
- MVC5 + EF6 入门完整教程(转载)--01
MVC5 + EF6 入门完整教程 第0课 从0开始 ASP.NET MVC开发模式和传统的WebForm开发模式相比,增加了很多"约定". 直接讲这些 "约定&qu ...
随机推荐
- 项目在UAP可以直接启动,但是在eclipse上面不能直接启动
上面两个eclipse都是用友的开发人员给我的,左边是驻场开发给我的,但是没有教我怎么用和哪里好用,所以一直用UAP来做开发.右边的eclipse是提ISM问题,北京用友远程调试问题时给我的,而且终于 ...
- 谷歌更新后,chromedriver如何更换新版本
前天,更新了78版本的谷歌后,chromedriver便不能用了,于是在ChromeDriver仓库下载了相对应版本的chromedriver. 并且放入谷歌文件下C:\Program Files ( ...
- JS基础-语法+流程控制语句+函数+内置对象【数组】
JS语法: Javascript基本数据类型:undefined/null/Boolean/number/string 复杂数据类型:object typeof用来检测变量的数据类型 typeof的使 ...
- Tensor--tensorflow的数据类型
在tensorflow2.0版本之前,1.x版本的tensorflow的基本数据类型有计算图(Computation Graph)和张量(Tensor)两种,但tensorflow2.0之后的版本取消 ...
- Deepin Linux下安装安卓应用的各种方式
没事啥折腾 Deepin Linux 的应用商店里集成了挺多安卓应用 , 没有的就只能自己想办法了. 我主要使用这几个app , 飞书,邮箱大师,还有一些公司内部app. 网上 搜索了一下 ,有以下几 ...
- 在生产环境中碰见的JSP木马-sunziren
写在前面,本文仅做为技术交流的用途,请不要使用本文中的技术破坏他人的网站及系统,因为这是违法的!!!本人不负任何法律责任!!! 19年1月份,发现了一个JSP木马文件,当时觉得有点奇怪的是,这个文件没 ...
- while else ,pass执行else,break不执行else
count = 0while count <=5: count += 1 if count == 3:pass print("Loop".count) else: print ...
- 【5】激活函数的选择与权值w的初始化
激活函数的选择: 西格玛只在二元分类的输出层还可以用,但在二元分类中,其效果不如tanh,效果不好的原因是当Z大时,斜率变化很小,会导致学习效率很差,从而很影响运算的速度.绝大多数情况下用的激活函数是 ...
- PAT 基础编程题目集 6-10 阶乘计算升级版 (20 分)
本题要求实现一个打印非负整数阶乘的函数. 函数接口定义: void Print_Factorial ( const int N ); 其中N是用户传入的参数,其值不超过1000.如果N是非负整数,则该 ...
- 关于java静态存储类的一个知识点
今天在写代码的时候产生了一个很奇怪的问题:静态类里的数据在其他类中更改之后,是否会保存 然后就动手试验了一下,结果是 ·在更改数据的类中,输出数据都是更够以后的数据 ·在先执行更改数据的类之后执行第二 ...