[TOC]
前言
写了一个.Net MVC的个人笔记,但是不是MarkDown,好难受,博客园也不支持以前的旧文章转MarkDown,以后有时间看看能不能整理一下,这次新开一个MarkDown的
母版页节点
在母版页的footer里面写
<footer>
@RenderSection("Footer")
</footer>
然后在子页中写
@section Footer{
<h3>大家好,我是脚</h3>
}
这样就可以把子页的内容放到母版页的节点位置了
Controller将数据传给View的方式
ViewBag和ViewData共享数据
public ActionResult Index () {
ViewBag.UserName = "小李飞刀";
ViewData["UserName"] = "陆小凤";
TempData["UserName"] = "楚留香"; //临时数据
User model = new User { UserName = "谢晓峰" };
return View (model); //这行代码其实就相当于ViewData.Model=model
}
View代码
@{
ViewBag.Title = "Index";
}
<div>@ViewBag.UserName </div>
<div>@ViewData["UserName"] </div>
<div>@TempData["UserName"] </div>
<div>@Model.UserName</div>
结果是:
陆小凤
陆小凤
楚留香
谢晓峰
原因是ViewData和ViewBag本质上都是【ViewDataDictionary】类型,并且两者之间的数据共享,只不过提供了不同的语法操作方式而已。所以“陆小凤”覆盖了原先的值”小李飞刀“。
TempData使用一次之后会立即删除数据
至于Model,在视图里面可以直接使用@Model.username进行使用,但是你会发现没有提示,这个是因为编译器无法在编译的时候获取Model的类型,如果想要提示可以这样做,在视图的上面写上@model是user类型的,注意必须是@model小写的,不能是@Model
@model User
Visual Studio不显示添加的文件
有的时候我在项目的文件夹里加了一些文件,但是Visual Studio不显示,明明已经加了,就是不显示,这时候可以点击显示所有文件按钮,如下图
点击了这个按钮,所有的文件都会显示了
Ajax
Ajax在.net MVC中用的非常多,一般是用来从后端获取数据,然后无刷新加载,Ajax的特点就是无刷新加载
普通的Ajax使用方法
基本上使用Ajax都是使用Jquery的Ajax,所以Jquery的js文件引用一下,最好放在母版页里面,这样所有的子页直接开写
获取文本内容加载
前端,Razor
@{
ViewBag.Title = "Index";
}
<h2>我是学习ajax的页面</h2>
<div>
<p id="text">我是字段</p>
<button id="ctbtn">传统ajax</button>
</div>
<script>
$(function () {
$('#ctbtn').click(function () {
$.post('/Ajax/GetData', { id: 666 }, function (data, status) {
$('#text').html(data + ' 状态是:' + status);
});
});
});
</script>
后端:
public ActionResult GetData(int id) {
return Json("普通的Ajax"+id,JsonRequestBehavior.AllowGet);
}
其实前端的ajax有三种,load,get和post,也可以写成
<script>
$(function () {
$('#ctbtn').click(function () {
$.get('/Ajax/GetData', { id: 666 }, function (data, status) {
$('#text').html(data + ' 状态是:' + status);
});
});
});
</script>
获取Model数组类型加载
新建一个Model,我新建的是User,如下
public class User
{
public string Name { get; set; }
public string Sex { get; set; }
public int Phone { get; set; }
}
然后前端Razor如此:
<script>
$(function () {
$('#ctbtn').click(function () {
$.post('/Ajax/GetData', { id: 666 }, function (data, status) {
$.each(data, function (key, value) {
//console.log(data[key].Name); 不需要再使用data了,可以直接使用value,这个value就是一个User对象,后面的属性记得保持一致,没有提醒
console.log(value.Name);
});
});
});
});
</script>
后端返回一个Json就可以了
public ActionResult GetData(int id) {
List<User> userList = new List<User>()
{
new User(){ Name="蜀云泉",Sex="男",Phone=123 },
new User(){ Name="许嵩",Sex="男",Phone=123 },
new User(){ Name="林俊杰",Sex="男",Phone=123 }
};
return Json( userList );
}
看看效果图
非入侵式Ajax(Unobtrusive Ajax)
这个简单的介绍一下,什么是非入侵式,就是前端页面只有纯粹的HTML和CSS,HTML元素里面没有一丁点的JavaScript,比如onclick方法之类的,所有的JavaScript都是单独的一个文件,这就是非入侵式,但是,根据我目前的水平来看,根据我目前接触的项目来看,JavaScript都是写在Razor里面的,并没有做到非入侵式,所以简单的介绍一下
打开.Net MVC的web.config文件,你可以发现如下
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
这两行就是开启客户端验证和非入侵式JavaScript的
如果只想在指定页面关闭非入侵式,可以在页面写
@{ Html.EnableUnobtrusiveJavaScript(false); }
@{ Html.EnableClientValidation(false); }
==讲真这个非入侵式开启关闭什么的,我是没有看懂的,有什么用?==
AjaxHelper
这个是封装的,分为异步连接按钮和异步表单,知道了就行了,感觉用的不多,不学
MVC Areas 区域
为什么会有Areas?因为多人协作,比如一个网站,我做购物车,你做商品管理,他做权限验证,如果使用普通的都在Controller文件夹里面新建Controller,在View文件夹里新建View,你会发现,好乱啊
Areas出现了,我做购物车,使用购物车Areas,你做商品管理,使用商品管理Areas
当然,首先每个部分都得有一定的复杂度,要是很简单的几个Controller就完成的模块,就不要分Areas了
新建Areas
新建一个AdminAreas,新建完成之后如下
点开AdminAreaRegistration看看,很明显里面的路由变成了Controller前面加了Admin
在Admin这个区域里面的Controller新建index,运行,都是一样的
不知道发现了没,看看上图,除了路由的文件多加了一个Admin,其他的文件夹很明显的三层,Controller,Model,View,所以Areas其实就相当于新建了一个文件夹而已,都是在项目内
把Areas转移到类库
先说一下,转移到类库有什么好处.首先,还是我上面说的,具备一定复杂度的模块才会新建一个Areas,两三个Controller就可以实现的模块没必要新建Areas
那么问题来了,多人协作的时候,我在Admin的Areas里面新建东西,写代码,测试,我一提交,那么StudyMVC这个项目的人就得获取我的代码,就得编译,万一我的AdminAreas有bug,他必须等我修复bug
新建一个类库就不一样了,我StudyMVC引用了你这个类库,你类库有问题不影响我的主项目,你编译你自己的,我编译我自己的
新建.Net FrameWork类库
我第一次没看清,新建的是.Net Standard,坑死了啊,选Net FrameWork类库
然后把StudyMVC里面的AdminAreas里面的AdminAreaRegistration.cs复制到外面类库AdminAreas里面,复制之后,会报错,这是因为必须引用两个文件
第一个using System.Web.Mvc,使用Nuget引用本地的就行
第二个using System.Web,这个就更简单了,直接在类库的引用上面右键添加引用就可以了
AdminAreaRegistration.cs文件复制到类库之后,原项目里面的就删了,原项目StudyMVC右键添加服务引用,引用AdminAreas这个类库
然后再来运行一下,输入Admin这个区域加上原项目的Controller,发现运行一样是ok的
如果你没有运行成功,请再次检查你的MVC项目有没有引用区域类库
==重点来了==
我现在在AdminAreas类库里面新建一个文件夹,叫Controller,然后新建一个Controller叫UserController,可能你无法新建控制器,可以从StudyMVC项目里面复制一个控制器过来,改改名字就好了
UserController里面新建一个Index方法,然后在MVC项目的Admin区域里面的View里面新建对应的User文件夹,下面新建Index.cshtml
给你们看看代码吧
首先外部AdminAreas类库的UserController
using System.Web.Mvc;
namespace StudyMVC.Areas.Admin.Controllers
{
public class UserController : Controller
{
// GET: Admin/AreaTest
public ActionResult Index()
{
ViewBag.user = "我是区域类库里面的UserController";
return View();
}
}
}
然后,我是MVC项目里面的index.cshtml
@{
Layout = null;
}
<h2>什么东西</h2>
<h2>@ViewBag.user</h2>
最后,结果大图
我讲一下,这个区域啊,放到外部的类库之后,就好多了.我的Admin区域的Controller在类库里,随便过来一个程序员,你改吧,只要符合我的前端cshtml的要求,返回值不要动,其他的逻辑代码你随便改
而且,改完之后,你自己在类库里面编译,编译成功后把dll丢给我的MVC项目就可以了
看到这里,可能有人会有疑问,为什么Controller丢在外面的类库,视图cshtml还在MVC 内部呢?
因为Controller是代码需要编译.....
视图cshtml不需要编译......
而且视图一旦写好了,不会经常修改的,反而是后台,会需要修修改改,所以我只需要定好我这个前端cshtml需要的返回值,你类库那边的Controller怎么写我不关心,只要返回值给对就行
我终于学会了Areas了
对象加问号判断是否为空
代码如下:
User user = null;
if (user?.Name=="蜀云泉")
{
Console.WriteLine("测试");
}
如果我不加?的话,因为user对象是null,所以我调用user.Name的时候会直接报错
对象后接一个?就是判断是否为空的意思,如果是空的话就不会执行判断了,很好用
过滤器
过滤器一般用来做身份验证,比如购物电商网站,你在购买的时候会检测你是否登录,如果没登录就让你登录,还有其他很多地方需要身份验证的,如果你每个地方都写一次身份验证的代码,那就违背DRY原则了,代码重复了
所以,有了过滤器,这个相当于AOC切面编程
三种过滤器
- ActionFilterAttribute:方法执行之前后和结果执行之前后
- AuthorizeAttribute:首先执行,在所有方法或过滤器之前
- HandleErrorAttribute:异常过滤器
我不会详细介绍,网上大把,我简单的说一下怎么用
新建过滤器
一般都是在Filter文件夹下面新建,我的
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace StudyMVC.Filter
{
/// <summary>
/// 这是我写的第一个过滤器,过滤器通常用在身份验证吧我感觉,F12进去看看ActionFilterAttribute就知道了
/// </summary>
public class MyCustomerFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.HttpContext.Response.Write("方法执行之前");
base.OnActionExecuting(filterContext);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
filterContext.HttpContext.Response.Write("方法执行之后");
base.OnActionExecuted(filterContext);
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Write("视图加载之前");
base.OnResultExecuting(filterContext);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
filterContext.HttpContext.Response.Write("视图加载之后");
base.OnResultExecuted(filterContext);
}
}
}
为什么我会这么写?因为你在ActionFilterAttribute上按下F12,查看源代码就知道了,如下
#region 程序集 System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// 未知的位置
// Decompiled with ICSharpCode.Decompiler 4.0.0.4285
#endregion
namespace System.Web.Mvc
{
//
// 摘要:
// Represents the base class for filter attributes.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IResultFilter
{
//
// 摘要:
// Called by the ASP.NET MVC framework before the action method executes.
//
// 参数:
// filterContext:
// The filter context.
public virtual void OnActionExecuting(ActionExecutingContext filterContext)
{
}
//
// 摘要:
// Called by the ASP.NET MVC framework after the action method executes.
//
// 参数:
// filterContext:
// The filter context.
public virtual void OnActionExecuted(ActionExecutedContext filterContext)
{
}
//
// 摘要:
// Called by the ASP.NET MVC framework before the action result executes.
//
// 参数:
// filterContext:
// The filter context.
public virtual void OnResultExecuting(ResultExecutingContext filterContext)
{
}
//
// 摘要:
// Called by the ASP.NET MVC framework after the action result executes.
//
// 参数:
// filterContext:
// The filter context.
public virtual void OnResultExecuted(ResultExecutedContext filterContext)
{
}
}
}
里面说的很明白了,方法执行前后,和结果执行前后
使用过滤器
因为过滤器是AOC面向切面编程的产物,所以使用很方便,有三种方式,不过最常用的还是在方法上加,其他两个一个是在Controller上加,一个是在全局过滤器加,不讲。
[MyCustomerFilter]
public ActionResult Index()
{
string test = string.Format("{0:P0}", 0.24583);
return View();
}
就是这么简单,Index这个方法已经加上过滤器了,
缓存
这里讲一下OutputCache这个缓存
我在Index方法上加上OutputCache缓存,如下
[OutputCache(Duration =5)]
public ActionResult Index()
{
ViewBag.time = DateTime.Now.ToString();
Response.Cache.SetOmitVaryStar(true);
return View();
}
Duration这个属性是时间,就是缓存几秒的意思,属性有很多,不写,去网上查
运行,发现,网络是200,然后我刷新一次,发现是304,如下图
这个304就是从缓存读取的意思,因为我设置了Duration缓存时间为5秒,所以,你在5秒内刷新都是304,过了5秒就又变成200了
SEO
SEO,搜索引擎优化。做网站最看重的就是SEO了吧,这关乎到你的网站在搜索引擎中的权重,SEO做的好,就会出现在搜索引擎的前几名,对网站的流量和知名度影响很大
开发时要考虑SEO
蜘蛛只爬取静态HTML
JavaScript动态生成的HTML,蜘蛛是不会爬取的,蜘蛛就是各大搜索引擎获取网站信息的工具,说到这里我想到了一点,Bootstrap Table这个插件是在js里面生成表格的,这样蜘蛛就不会爬取,SEO会变差
使用a标签,不要使用LinkButton
因为搜索引擎蜘蛛只认a标签,不认JavaScript,例如
<a href="javascript:document.location='www.baidu.com'">百度</a>
这个搜索引擎的蜘蛛是不认的,而LinkButton就是这个
Lucene.Net分词
WebService
WebService是什么暂且不细说,先看看怎么新建最简单的WebService
新建空的EntityFramework网站
直接右键新建空的EntityFramework网站,没什么好说的
新建WebService
这个新建Web服务即可,如图
我的命名是MyWebService,双击打开可以看到里面已经有了一个HelloWorld方法
现在我们来新加一个方法,如下:
[WebMethod]
public int Multiplier(int a,int b)
{
return a * b;
}
直接在MyWebService右键,在浏览器中运行,如图
超经典的图面了,这就是WebService了,你点击Multiplier,还可以直接在线测试方法
调用WebService
首先,项目先引用WebService,直接在引用那里,右键添加服务引用,选择我们刚才的WebService地址即可,注意,这里引用的地址不要和WebService重名了
然后新建一个Razor页面来测试吧,单纯的HTML没办法写C#,还是Razor好用
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title></title>
</head>
<body>
<div>
@{
WebService.ServiceReference.MyWebServiceSoapClient client = new WebService.ServiceReference.MyWebServiceSoapClient();
<text>@client.Multiplier(5,6)</text>
}
</div>
</body>
</html>
直接右键运行这个Razor,可以直接看到30,至此,最简单的WebService创建和调用完成了
调用网络上的WebService
这个有点坑啊,本地的WebService是直接添加服务引用,网络上的不一样,需要点击添加服务引用,点击高级=>添加Web引用才可以,如下图,网络的WebService带有Web
我们这里以天气服务助手为例,网上搜一下天气服务助手,可以搜到这个
http://www.webxml.com.cn/WebServices/WeatherWS.asmx
你可以点着看看各个接口是干嘛的,我不介绍了,直接调用,还是在我很喜欢的Razor里面
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title></title>
</head>
<body>
<div>
@{
WebService.WeatherService.WeatherWS weatherClient = new WebService.WeatherService.WeatherWS();
string[] text = weatherClient.getWeather("深圳", "");
foreach (var item in text)
{
<text> @item </text>
}
}
</div>
</body>
</html>
不知道发现了没,这个getWeather接口也是坑,明明两个参数,一个是城市名,一个是城市的编号ID,但是输入ID却没有身份验证....所以上面的几个接口都是获取Id的有什么用???我直接输入城市名就获取了.....
看看结果
根据下拉框内容更新表格
下拉框怎么获取枚举的值
肯定不能写死数据了,所以从枚举获取值最好
<select class="form-control input-sm" id="adjustStatus">
<option value="-1">调整状态</option>
@foreach (var item in Enum.GetValues(typeof(ProductSaleStatus)))
{
<option value="@item.GetHashCode()">@item</option>
}
</select>
获取表格选择的Id,下拉框的点击事件
$('#adjustStatus').on("click", function () {
if ($('#adjustStatus').val() == -1) {
return
}
id = [];
$('input[name="checkbox"]:checked').each(function () {
if ($(this).prop("checked")) {
id.push($(this).val());
}
})
if (id.length > 0) {
var ids = id.join(",");
$.ajax({
type: "post",
url: "/ProductSale/AdjustSaleStatus",
data: { ids: ids, status: $('#adjustStatus').val() },
success: function (data) {
if (data.Status == 1) {
layer.alert(data.Message, { title: '提示', icon: 1, time: 10000});
# 刷新页面
window.location.reload()
}
},
error: Common.Public.Error
});
} else {
layer.alert("请最少选择一条销售记录", { title: '提示', icon: 2, time: 5000, anim: 6 });
}
# 最后,把我的下拉框恢复原样,不然点一次又执行了
$('#adjustStatus').val(-1)
});
最好的方法
还可以使用更好的方法,如下
//这个是HTML
<td>
<select class="adjustStatus">
@foreach (var item in Enum.GetValues(typeof(ChatMessageStatus)))
{
<option value="@item.GetHashCode()" @if ((int)chatMessage.Status == item.GetHashCode()) { <text> selected</text> }>@item</option>
}
</select>
</td>
//这个是js
$('.table tbody').on('change', 'tr .adjustStatus', function () {
$.ajax({
type: "post",
url: "/Messenger/AdjustStatus",
data: { id: $(this).parents("td").attr("id"), status: $(this).val() },
success: function (data) {
if (data.Result == "succeed") {
window.location.reload()
}
},
});
});
枚举的值怎么显示为中文
一般来说,枚举的值在数据库中都是一个int类型的字段,里面存储0123这样的数字
然后枚举是类似这样的,一般都在类上面写了
public enum People
{
许嵩 = 0,
蜀云泉 = 1
}
添加一个枚举类型的字段,给个默认值
public People people { get; set; } = People.许嵩;
前端页面使用的时候,直接调用,因为字段本身就是枚举的,所以显示的时候显示的就是中文
<td>@chatMessage.people</td>
Bootstrap的table点击下一页js不可以使用
使用了Bootstrap的一个table插件,发现点击下一页之后,js不起作用了
例如我下面的表格里面的一个class是people,我直接使用.people不行,下一页js根本不生效,换成下面那种就可以了
//$('.people').on("click", function () {
//将上面的换成下面的,就可以了
$('.table tbody').on('click', 'tr .people' , function () {
查看用户是从哪个页面过来的
if (HttpContext.Current.Request.UrlReferrer != null)
{
rurl = HttpContext.Current.Request.UrlReferrer.AbsoluteUri;
}
插入数据后返回该数据的id
代码里面写的是bool,我就很奇怪,我还得再写一个返回int类型的方法?
但是我万万没想到, customer.CustomerId = id;这一行代码就已经返回了id了
public bool AddCustomer(Customer customer)
{
string strSql = @"insert into Customer(company,contact) values (@company,@contact);Select @@Identity";
DbParameter[] cmdParms = {
_helper.CreateInDbParameter("company", DbType.String,customer.Company),
_helper.CreateInDbParameter("contact", DbType.String,customer.Contact)};
int id = _helper.GetInt(_helper.ExecuteScalar(CommandType.Text, strSql.ToString(), cmdParms));
customer.CustomerId = id;
return id > 0;
}
IIS部署https
在使用push.js进行通知提醒的时候,使用本地的IIS部署的项目无法测试,因为push.js只能在https这样的请求头下工作,所以新加一个IIS部署为https即可
选择网站,点击右侧的绑定,出来一个网站绑定,选择https即可,如图
选择https,输入本机ip,默认443端口,最下面的证书可以选择IIS
然后访问网址直接输入https://192.168......即可
使用JSON JavaScriptSerializer 进行序列化或反序列化时出错。字符串的长度超过了为 maxJsonLength属性
只需要把代码改为以下
return new JsonResult() {
Data = new { total, rows },
MaxJsonLength = int.MaxValue,
ContentType = "application/json",
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
使用KeyName
使用KeyName真的是太必要了,有的Name里面是有奇怪的字符的,显示效果太差,所以需要KeyName
public static string GetKeyName(this string name)
{
if (!string.IsNullOrWhiteSpace(name))
{
return name.Trim().Replace("~", "-").Replace("`", "-").Replace("!", "-").Replace("@", "-")
.Replace("#", "-").Replace("$", "-").Replace("%", "-").Replace("^", "-").Replace("&", "-").Replace("*", "-")
.Replace(" ", "-").Replace("(", "-").Replace(")", "-").Replace("+", "-").Replace("®", "-").Replace("™", "-")
.Replace("=", "-").Replace(",", "-").Replace(".", "-").Replace("<", "-").Replace(">", "-").Replace("’", "-").Replace(",", "-").Replace("±", "-").Replace("[", "-").Replace("]", "-")
.Replace("?", "-").Replace("/", "-").Replace("\\", "-").Replace(";", "-").Replace(":", "-").Replace("–", "-").Replace("ω", "-").Replace("{", "-").Replace("}", "-")
.Replace("'", "-").Replace("\"", "-").Replace("“", "-").Replace("”", "-").Replace("|", "-").Replace("_", "-").Replace("---", "-").Replace("--", "-").ToLower().Trim();
}
return "";
}
EntryFramework
EF有三种模式,分别是
DBFirst:数据库优先
ModelFirst:实体类优先
CodeFirst:代码优先
接下来分别介绍一下这三种模式
DB First方式
新建
数据库优先,那你得先有了数据库,有了业务需要的表,然后新建项,选择数据,实体数据模型,如图
接下来选择你的数据库,选择完成之后可以勾选哪些表生成Model
新建一个方法,测试一下EF
public void DBFirst(){ VaeDBEntities entity = new VaeDBEntities(); Movie movie = new Movie { Title = "测试DB", ReleaseDate = DateTime.Now, Genre = "测试", Price = 2 }; entity.Movie.Add(movie); entity.SaveChanges();}
执行一下即可,数据已经更新到表中了
entity.Movie.Add(movie);这条语句作用就是构造SQL语句,insert Movie Values ....
entity.SaveChanges();这句作用就是生成SQL语句然后去数据库执行
可以看到,EF其实就是我们写的代码转换成了SQL然后执行
EF的增删改查
延时加载
public void DBFirstQuery(){ using (VaeDBEntities entity = new VaeDBEntities()) { DbQuery dbQuery = entity.Movie.Where(x => x.ID == 1002) as DbQuery; Movie movie = dbQuery.FirstOrDefault(); Console.WriteLine(movie.Title); }}
代码如上,我使用的是SQLServer数据库,可以打开SqlServer Profiler,在工具菜单栏下
然后执行代码在这个方法里面打个断点,你会发现在查询结果dbQuery的时候SqlServer Profiler并没有SQL查询记录,在执行FirstOrDefault方法的时候才出现了执行的SQL语句
再举个例子,如下
public void DBFirstQuery2(){ using (VaeDBEntities entity = new VaeDBEntities()) { IQueryable dbQuery = entity.Movie.Where(x => x.ID == 1002); Movie movie = dbQuery.FirstOrDefault(); IQueryable movies = entity.Movie; foreach (var item in movies) { Console.WriteLine(item.Title); } }}
这个例子中,上面的movie还是和上个例子一样的,不过接受类型换成了IQueryable,在EF中查询的结果都是继承了IQueryable接口的,所以使用IQueryable接收也是ok的
重点是下面的一个查询集合
IQueryable movies = entity.Movie;
这句代码在SqlServer Profiler中没有SQL查询,仅仅是在拼接SQL,没有执行,当我运行到下一句代码的时候
foreach (var item in movies)
SQL会执行,也就是
select * from Movie
其后的遍历都不会生成SQL查询了,看看SqlServer Profiler的截图
EF的增删改查这些方法,例如
entity.Movie.Add(movie);entity.Movie.Remove(movie);entity.SaveChanges();
不管是Add还是Remove方法,都仅仅是标记,标记当前对象为新增状态或者删除状态,在执行SaveChanges方法的时候才是转化为SQL语句去数据库中执行了
批处理
public void DBFirstAdd(){ using (VaeDBEntities entity = new VaeDBEntities()) { Movie movie = new Movie { Title = "测试DB", ReleaseDate = DateTime.Now, Genre = "测试", Price = 2 }; entity.Movie.Add(movie); entity.Movie.Remove(movie); entity.SaveChanges(); }}
其实就是多次标记,一次SaveChanges
Linq To EF
public void LinQ(){ using (VaeDBEntities entity = new VaeDBEntities()) { var result = from c in entity.Movie select c; var result2 = from c in entity.Movie where c.ID == 1002 select c; //Lambda var result3 = entity.Movie.Where(c => c.ID == 1002); //排序 IQueryable movies = (from c in entity.Movie orderby c.ID select c).Skip(0).Take(10); //聚合函数 var max = entity.Movie.Max(x => x.ID); }}
这些Linq也只是生成了SQL语句,没有执行,使用的时候才会执行SQL,所以也算是延迟加载吧
Model First
还是新建项,选择数据>ADO.NET实体数据模型,然后选择空的EF设计模型即可,然后点击edmx文件,自己右键新建Model....
很明显,Model First适合什么都没有的情况下,没有数据表,没有实体类.我就不演示了,这种做法我不会用的
Code First
Code First适合已经存在了实体类,你可以借助于实体类生成数据表,这个有DataAnnotation方式和Fluent API方式,把已有Model生成数据表我也不想看了,不学
总结EF
总结一下EF,首先三个模式
DB First :有数据表,生成Model,并使用EF
Model First : 啥都没有,新建Model,生成数据表,使用EF
Code First : 有Model类了,生成数据表,使用EF
其中,我简单介绍了DB First,其他两个我不想看,在实际开发中,我都是先设计数据表,再进行开发的