• 【EF6学习笔记】(九)异步处理和存储过程


    本篇原文:Async and Stored Procedures

    为何要采用异步?

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

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

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

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

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

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

    更专业的资料: Use .NET 4.5's async support to avoid blocking calls.

    下面做些代码测试:

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

     

    自动生成的Index Action:

      public async Task<ActionResult> Index()
            {
                var departments = db.Departments.Include(d => d.Administrator);
                return View(await departments.ToListAsync());
            }

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

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

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

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

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

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

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

    复制代码
    @model IEnumerable<EFTest.Models.Department>
    
    @{
        ViewBag.Title = "Departments";
    }
    
    <h2>Departments</h2>
    
    <p>
        @Html.ActionLink("Create New", "Create")
    </p>
    <table class="table">
        <tr>        
            <th>
                @Html.DisplayNameFor(model => model.Name)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Budget)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.StartDate)
            </th>
            <th>
                Administrator
            </th>
            <th></th>
        </tr>
    
    @foreach (var item in Model) {
        <tr>        
            <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Budget)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.StartDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Administrator.FullName)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new { id=item.DepartmentID }) |
                @Html.ActionLink("Details", "Details", new { id=item.DepartmentID }) |
                @Html.ActionLink("Delete", "Delete", new { id=item.DepartmentID })
            </td>
        </tr>
    }
    
    </table>
    复制代码

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

    复制代码
         <div class="form-group">
                <label class="control-label col-md-2" for="InstructorID">Administrator</label>
                @*@Html.LabelFor(model => model.InstructorID, "InstructorID", htmlAttributes: new { @class = "control-label col-md-2" })*@
                <div class="col-md-10">
                    @Html.DropDownList("InstructorID", null, htmlAttributes: new { @class = "form-control" })
                    @Html.ValidationMessageFor(model => model.InstructorID, "", new { @class = "text-danger" })
                </div>
            </div>
    复制代码
    复制代码
    @model EFTest.Models.Department
    
    @{
        ViewBag.Title = "Delete";
    }
    
    <h2>Delete</h2>
    
    <h3>Are you sure you want to delete this?</h3>
    <div>
        <h4>Department</h4>
        <hr />
        <dl class="dl-horizontal">
            @*<dt>
                @Html.DisplayNameFor(model => model.Administrator.LastName)
            </dt>
    
            <dd>
                @Html.DisplayFor(model => model.Administrator.LastName)
            </dd>*@
            <dt>
                Administrator
            </dt>
            <dd>
                @Html.DisplayFor(model => model.Administrator.FullName)
            </dd>
            <dt>
                @Html.DisplayNameFor(model => model.Name)
            </dt>
    
            <dd>
                @Html.DisplayFor(model => model.Name)
            </dd>
    
            <dt>
                @Html.DisplayNameFor(model => model.Budget)
            </dt>
    
            <dd>
                @Html.DisplayFor(model => model.Budget)
            </dd>
    
            <dt>
                @Html.DisplayNameFor(model => model.StartDate)
            </dt>
    
            <dd>
                @Html.DisplayFor(model => model.StartDate)
            </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>
    复制代码

    DeleteDetail如上面修改方法;

    效果:

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

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

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

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

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

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

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

    复制代码
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Entity<Course>()
            .HasMany(c => c.Instructors).WithMany(i => i.Courses)
            .Map(t => t.MapLeftKey("CourseID")
                .MapRightKey("InstructorID")
                .ToTable("CourseInstructor"));
        modelBuilder.Entity<Department>().MapToStoredProcedures();
    }
    复制代码

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

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

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

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

    有3个存储过程被产生;

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

    现在采用的方式是EF Code First直接定义存储过程名的方式,如果要使用自己数据库中已有的存储过程,则参考:Entity Framework Code First Insert/Update/Delete Stored Procedures.

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

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

  • 相关阅读:
    亲们,知道你想更优秀,你做到这些了吗?
    Linux socket编程学习笔记(一):socket()函数详解
    关于typedef的用法总结
    c,c++里面,头文件里面的ifndef /define/endif的作用
    玩转ptrace
    文笔流畅,修辞得体
    定义和实现一个类的成员函数为回调函数
    《Shell 脚本学习指南 》 背景知识与入门 [第一、二章]
    使用ptrace跟踪进程
    FCKeditor 2.6.4.1配置
  • 原文地址:https://www.cnblogs.com/wyt007/p/8488856.html
Copyright © 2020-2023  润新知