java异步调用数据库存储过程详解_【EF6学习笔记】(九)异步处理和存储过程...

为何要采用异步?

一个Web服务器肯定有可用线程的限制,那么在一些访问量特别大的情况下,线程肯定会消耗完;这个时候服务器肯定处理不了请求,必须等线程里处理结束才可以处理请求;

在非异步的时候,很多线程都处于等待状态,并不是一直在工作,而是在等类似于I/O等处理结束;

采用异步的时候,当一个处理在等待I/O处理结束的时候,可以先去做做其他事情;

所以异步处理可以使服务器更为高效,较低延迟的情况下处理更多的请求。

在早期的.NET中,写或者测试异步处理都是很复杂的,庆幸的是.NET 4.5以后写或者测试异步处理请求代码都非常简单,除非有特别的理由不采用异步处理;

异步处理确实会有一些多出来的系统开销,对于低流量的应用,效果可以忽略,但对于大流量的应用,效果是很明显的;

下面做些代码测试:

采用异步方式新建Department控制器:

1bcca5dd5856bbf077f87462cd183cd0.png

自动生成的Index Action:

public async Task Index()

{

var departments = db.Departments.Include(d => d.Administrator);

return View(await departments.ToListAsync());

}

与非异步方式,有4处不同来实现EF异步请求数据:

1、请求方法加上了async标志关键字,等于告诉编译器这个方法中有部分方法体为异步的,需要生成针对部分方法体的异步回调,并且自动创建一个Task对象作为异步返回;

2、返回类型从ActionResult变为Task,Task表明后续处理将使用T类型;

3、await关键字引用于Call Web Service,当编译器看到await这个关键字,就会把这个方法分为两部分,第1部分就是开始异步处理,第2部分就是异步处理完成后,再回调的部分;

4、采用ToList的异步版本方法;

(原文后面一段没看明白。。。感觉有些笔误以及思路没理清楚)

接后面改几个视图,把Index视图里稍微改下,显示Administrator的全名:

4247438

@model IEnumerable@{

ViewBag.Title= "Departments";

}

Departments

@Html.ActionLink("Create New", "Create")

@Html.DisplayNameFor(model=>model.Name)@Html.DisplayNameFor(model=>model.Budget)@Html.DisplayNameFor(model=>model.StartDate)

Administrator

@Html.DisplayFor(modelItem=>item.Name)@Html.DisplayFor(modelItem=>item.Budget)@Html.DisplayFor(modelItem=>item.StartDate)

@Html.DisplayFor(modelItem => item.Administrator.FullName)

@Html.ActionLink("Edit", "Edit", new { id=item.DepartmentID }) |@Html.ActionLink("Details", "Details", new { id=item.DepartmentID }) |@Html.ActionLink("Delete", "Delete", new { id=item.DepartmentID })

4247438

把Create\Edit视图中 InstructorID 字段标题 改为 Administrator ,把原来一行注释掉,增加一行:

4247438

Administrator@*@Html.LabelFor(model => model.InstructorID, "InstructorID", htmlAttributes: new { @class = "control-label col-md-2" })*@

@Html.DropDownList("InstructorID", null, htmlAttributes: new { @class = "form-control"})

@Html.ValidationMessageFor(model=> model.InstructorID, "", new { @class = "text-danger"})

4247438

4247438

@model EFTest.Models.Department

@{

ViewBag.Title= "Delete";

}

Delete

Are you sure you want to delete this?

Department


@Html.DisplayNameFor(model=>model.Administrator.LastName)
@Html.DisplayFor(model=>model.Administrator.LastName)
Administrator
@Html.DisplayFor(model=>model.Administrator.FullName)
@Html.DisplayNameFor(model=>model.Name)
@Html.DisplayFor(model=>model.Name)
@Html.DisplayNameFor(model=>model.Budget)
@Html.DisplayFor(model=>model.Budget)
@Html.DisplayNameFor(model=>model.StartDate)
@Html.DisplayFor(model=>model.StartDate)
@using (Html.BeginForm()) {

@Html.AntiForgeryToken()

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

}

4247438

Delete\Detail如上面修改方法;

效果:

e9e0d21184d6718a8c892148a7d5f9f4.png

2a2965a2a0907c041c205fe05ad47306.png

看起来的效果和其他控制器一样。。。但这个控制器后台查询处理数据都是异步方式。

对于异步方式,有两点需要注意:

1、异步方式无法线程安全,换句话说,不要尝试同一个上下文实例来并行多次处理;

2、如果你要享受到异步方式的好处,记得所有使用到的并且涉及到数据库操作的类库(例如:分页)都需要采用异步方式;

采用存储过程来进行增删改

一些DBA比较推荐使用存储过程来进行数据操作,以前版本的EF只能通过存储过程取数据,更新数据做不到,而现在EF6就很简单可以实现;

把DAL文件夹中的SchoolContext.cs 中的OnModelCreating方法加入如下一行:

4247438

protected override voidOnModelCreating(DbModelBuilder modelBuilder)

{

modelBuilder.Conventions.Remove();

modelBuilder.Entity()

.HasMany(c=> c.Instructors).WithMany(i =>i.Courses)

.Map(t=> t.MapLeftKey("CourseID")

.MapRightKey("InstructorID")

.ToTable("CourseInstructor"));

modelBuilder.Entity().MapToStoredProcedures();

}

4247438

这样EF就会采用存储过程进行Department的操作;

首先先要数据库升级一下,建立好存储过程;在PMC中输入 add-migration DepartmentSP

然后在数据库迁移目录里就可以看到最新的日期时间戳的XXXXXXXXXXXXX_DepartmentSP.sc文件,打开这个文件就可以看到里面向数据库里增加了3个存储过程;

在PMC中输入update-database,执行完的结果,可以到数据库里查看:

e07857bab8980ffeb8f6170f4367452b.png

有3个存储过程被产生;

其他代码都不用改动,在执行Department增删改的时候,EF会自动调用这个存储过程来进行。

如果想自己定制存储过程的产生,可以在迁移中定义的up方法中来修改。

如果要改变一个已有的以前版本建立的存储过程,可以使用Add-Migration创建一个空的迁移,然后在一个叫AlterStoredProcedure方法中手动写代码;


版权声明:本文为weixin_39626586原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。