MVC + EF asynchronous CRUD

I. Introduction

In previous articles, we mainly on the TPL, primarily Task, and also describes how to use asynchronous methods in ASP.NET MVC, in this article, we combine a small example, using ASP.NET MVC + EF, asynchronous CRUD.

Second, the function realization

Our students, for example, implement CRUD functionality.

1, the UI layer structures

Here we use ASP.NET MVC to display the data as an interface layer, first create a solution, then add a MVC project, named TaskAsync.UI, after the project structure created as shown below:

2, was added entity class

We separate entity class library in which, a new type of item, name TaskAsync.Model, which has a Student class, Student class code as follows:

namespace TaskAsync.Model
{
    /// <summary>
    /// 学生类
    /// </summary>
    public class Student
    {
        /// <summary>
        /// 主键
        /// </summary>
        public int Id { get; set; }

        /// <summary>
        /// 姓名
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 年龄
        /// </summary>
        public int Age { get; set; }

        /// <summary>
        /// 性别
        /// </summary>
        public int Gender { get; set; }
    }
} 

3, add the service interface layer

We CRUD methods defined in the interface inside, add a new type of project, named TaskAsync.IService, libraries need to refer to an entity created above. There is a IStudentService interface, the interface code is as follows:

using System.Collections.Generic;
using System.Threading.Tasks;
using TaskAsync.Model;

namespace TaskAsync.IService
{
    public interface IStudentService
    {
        /// <summary>
        /// 增加的异步方法
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        Task<int> AddPersonAsync(Student entity);

        /// <summary>
        /// 删除的异步方法
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        Task<int> DeleteByIdAsync(int id);

        /// <summary>
        /// 获取所有数据
        /// </summary>
        /// <returns></returns>
        Task<IEnumerable<Student>> GetAllAsync();

        /// <summary>
        /// 根据Id获取单一值
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        Task<Student> GetStudentByIdAsync(int id);

        /// <summary>
        ///</ Summary>///Update asynchronous method
        /// 
         <param name="entity"></param>
        /// <returns></returns>
        Task<int> UpdateAsync(Student entity);
    }
}

All methods return values ​​are Task <T> type, name of the default method of ending the Async, denoted as asynchronous method. 

4. Add Entity Framework

We use EF as ORM framework, the EF in a separate class library which named TaskAsync.Data. NuGet directly installed inside:

 After installation is complete, we also need to create a program in ASP.NET MVC inside EntityFramework, then add the connection string in the Web.config file inside the outer layer:

  <connectionStrings>
    <add name="EFContext" connectionString="Data Source=.;Initial Catalog=TaskAsyncDb;User ID=sa;Password=123456;" providerName="System.Data.SqlClient" />
  </connectionStrings>

注意:链接字符串里面的providerName不能省略,否则进行数据迁移的时候会报错。

我们在TaskAsync.Data项目里面添加数据上下文类,继承自父类的DbContext:

using System.Data.Entity;
using TaskAsync.Model;

namespace TaskAsync.Data
{
    /// <summary>
    /// 数据上下文类,继承自父类的DbContext
    /// </summary>
    public class AppDbContext:DbContext
    {
        /// <summary>
        /// 通过创建连接,给父类的构造函数传递参数
        /// 参数是连接字符串的名称
        /// 表示使用连接字符串中名字为DbConnectionString的去连接数据库
        /// </summary>
        public AppDbContext():base("name=DbConnectionString")
        {

        }

        /// <summary>
        /// 重写OnModelCreating方法
        /// </summary>
        /// <param name="modelBuilder"></param>
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            // 配置生成的表名
            modelBuilder.Entity<Student>().ToTable("T_Student");
            base.OnModelCreating(modelBuilder);
        }

        public DbSet<Student> Students { get; set; }
    }
}

数据上下文类创建完成以后,我们接下来在程序包管理器控制台里面进行数据迁移:

注意:项目要选择EntityFramework所在的类库项目。

1、开启迁移

使用下面的命令开启数据迁移:

Enable-Migrations

命令执行如下图所示:

2、增加迁移

使用下面的命令开始迁移:

Add-Migration Init

命令执行如下图所示:

执行成功以后,会在TaskAsync.Data项目下面添加一个Migrations文件夹

这个文件夹下面有两个类文件:Configuration.cs文件里面是配置信息,另外一个是本次迁移记录文件。我们在Configuration.cs类里面添加一些种子数据:

namespace TaskAsync.Data.Migrations
{
    using System.Collections.Generic;
    using System.Data.Entity.Migrations;
    using System.Linq;
    using TaskAsync.Model;

    internal sealed class Configuration : DbMigrationsConfiguration<TaskAsync.Data.AppDbContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }

        protected override void Seed(TaskAsync.Data.AppDbContext context)
        {
            List<Student> list = new List<Student>()
            {
                new Student()
                {
                    Name="Jack",
                    Age=23,
                    Gender=1
                },
                new Student()
                {
                    Name="Tom",
                    Age=25,
                    Gender=2
                }
            };

            if(!context.Students.Any())
            {
                context.Students.AddRange(list);
            }
        }
    }
}

3、生成数据库

我们在上面配置完成以后,就可以使用下面的命令去生成数据库:

Update-Database

命令执行如下图所示:

命令执行成功,就会自动创建数据库和表,表里面插入我们添加的种子数据:

5、添加接口的实现类

我们添加IStudentService接口的实现类。添加一个单独的类库,命名为TaskAsync.Service,并添加对TaskAsync.Model、TaskAsync.IService、TaskAsync.Data的引用,然后实现IStudentService接口:

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TaskAsync.Data;
using TaskAsync.IService;
using TaskAsync.Model;

namespace TaskAsync.Service
{
    public class StudentService : IStudentService
    {
        /// <summary>
        /// 新增 方法标注为async
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task<int> AddPersonAsync(Student entity)
        {
            using (AppDbContext dbContext = new AppDbContext())
            {
                dbContext.Students.Add(entity);
                // 调用异步方法
                int count = await dbContext.SaveChangesAsync();
                return count;
            }
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<int> DeleteByIdAsync(int id)
        {
            using (AppDbContext dbContext = new AppDbContext())
            {
                Student student =await dbContext.Students.FindAsync(new object[] { id });
                if(student!=null)
                {
                    dbContext.Students.Remove(student);
                    return await dbContext.SaveChangesAsync();
                }
                else
                {
                    return 0;
                }
            }
        }

        public async Task<IEnumerable<Student>> GetAllAsync()
        {
            List<Student> list = await Task.Run<List<Student>>(() => 
            {
                using (AppDbContext dbContext = new AppDbContext())
                {
                    return dbContext.Students.ToList();
                }
            });

            return list;
        }

        public async Task<Student> GetStudentByIdAsync(int id)
        {
            using (AppDbContext dbContext = new AppDbContext())
            {
                Student student = await dbContext.Students.FindAsync(new object[] { id });
                if (student != null)
                {
                    return student
                }
                else
                {
                    return null;
                }
            }
        }

        public async Task<int> UpdateAsync(Student entity)
        {
            using (AppDbContext dbContext = new AppDbContext())
            {
                Student student = await dbContext.Students.FindAsync(new object[] { entity.Id });
                if (student != null)
                {
                    student.Name = entity.Name;
                    student.Age = entity.Age;
                    student.Gender = entity.Gender;
                    dbContext.Entry(student).State = System.Data.Entity.EntityState.Modified;
                    return await dbContext.SaveChangesAsync();
                }
                else
                {
                    return 0;
                }
            }
        }
    }
}

注意:这里同样需要添加到EntityFramework的引用。

6、添加控制器

我们在ASP.NET MVC项目里面首先添加对上面几个类库的引用。

为了测试方法,我们直接添加一个包含视图的MVC5控制器(使用Entity Framework),这样就会自动生成UI界面了,如下图所示:

 模型类选择Student,数据上下文类选择AppDbContext,如下图所示:

创建完成之后,会看到自动添加了视图:

控制器里也自动生成了代码:

using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using TaskAsync.Data;
using TaskAsync.Model;

namespace TaskAsync.UI.Controllers
{
    public class StudentController : Controller
    {
        private AppDbContext db = new AppDbContext();

        // GET: Student
        public ActionResult Index()
        {
            return View(db.Students.ToList());
        }

        // GET: Student/Details/5
        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Student student = db.Students.Find(id);
            if (student == null)
            {
                return HttpNotFound();
            }
            return View(student);
        }

        // GET: Student/Create
        public ActionResult Create()
        {
            return View();
        }

        // POST: Student/Create
        // 为了防止“过多发布”攻击,请启用要绑定到的特定属性,有关 
        // 详细信息,请参阅 https://go.microsoft.com/fwlink/?LinkId=317598
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "Id,Name,Age,Gender")] Student student)
        {
            if (ModelState.IsValid)
            {
                db.Students.Add(student);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            return View(student);
        }

        // GET: Student/Edit/5
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Student student = db.Students.Find(id);
            if (student == null)
            {
                return HttpNotFound();
            }
            return View(student);
        }

        // POST: Student/Edit/5
        // 为了防止“过多发布”攻击,请启用要绑定到的特定属性,有关 
        // 详细信息,请参阅 https://go.microsoft.com/fwlink/?LinkId=317598
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "Id,Name,Age,Gender")] Student student)
        {
            if (ModelState.IsValid)
            {
                db.Entry(student).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(student);
        }

        // GET: Student/Delete/5
        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Student student = db.Students.Find(id);
            if (student == null)
            {
                return HttpNotFound();
            }
            return View(student);
        }

        // POST: Student/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            Student student = db.Students.Find(id);
            db.Students.Remove(student);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}

但是框架生成的代码都是同步方法的,不是我们需要的,我们改成异步的方法:

using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web.Mvc;
using TaskAsync.Data;
using TaskAsync.IService;
using TaskAsync.Model;
using TaskAsync.Service;

namespace TaskAsync.UI.Controllers
{
    public class StudentController : Controller
    {
        //private AppDbContext db = new AppDbContext();

        IStudentService service = new StudentService();
        // GET: Student
        public async Task<ActionResult> Index()
        {
            return View(await service.GetAllAsync());
        }

        // GET: Student/Details/5
        public async Task<ActionResult> Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Student student =await service.GetStudentByIdAsync((int)id);
            if (student == null)
            {
                return HttpNotFound();
            }
            return View(student);
        }

        // GET: Student/Create
        public ActionResult Create()
        {
            return View();
        }

        // POST: Student/Create
        // 为了防止“过多发布”攻击,请启用要绑定到的特定属性,有关 
        // 详细信息,请参阅 https://go.microsoft.com/fwlink/?LinkId=317598
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async  Task<ActionResult> Create([Bind(Include = "Id,Name,Age,Gender")] Student student)
        {
            if (ModelState.IsValid)
            {
                int count = await service.AddPersonAsync(student);
                if(count>0)
                {
                    return RedirectToAction("Index");
                }
            }

            return View(student);
        }

        // GET: Student/Edit/5
        public async Task<ActionResult> Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Student student = await service.GetStudentByIdAsync((int)id);
            if (student == null)
            {
                return HttpNotFound();
            }
            return View(student);
        }

        // POST: Student/Edit/5
        // 为了防止“过多发布”攻击,请启用要绑定到的特定属性,有关 
        // 详细信息,请参阅 https://go.microsoft.com/fwlink/?LinkId=317598
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Edit([Bind(Include = "Id,Name,Age,Gender")] Student student)
        {
            if (ModelState.IsValid)
            {
                int count = await service.UpdateAsync(student);
                if (count > 0)
                {
                    return RedirectToAction("Index");
                }
            }
            return View(student);
        }

        // GET: Student/Delete/5
        public async  Task<ActionResult> Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Student student = await service.GetStudentByIdAsync((int)id);
            if (student == null)
            {
                return HttpNotFound();
            }
            return View(student);
        }

        // POST: Student/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> DeleteConfirmed(int id)
        {
            int count = await service.DeleteByIdAsync(id);
            return RedirectToAction("Index");
        }

        //protected override void Dispose(bool disposing)
        //{
        //    if (disposing)
        //    {
        //        db.Dispose();
        //    }
        //    base.Dispose(disposing);
        //}
    }
}

然后我们在修改_Layout.cshtml视图文件,添加学生管理的一个标签:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - 我的 ASP.NET 应用程序</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
</head>
<body>
    <div class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                @Html.ActionLink("应用程序名称", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li>@Html.ActionLink("主页", "Index", "Home")</li>
                    <li>@Html.ActionLink("关于", "About", "Home")</li>
                    <li>@Html.ActionLink("联系方式", "Contact", "Home")</li>
                    <li>@Html.ActionLink("学生管理", "Index", "Student")</li>
                </ul>
            </div>
        </div>
    </div>
    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; @DateTime.Now.Year - 我的 ASP.NET 应用程序</p>
        </footer>
    </div>

    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
</body>
</html>

运行程序,点击“学生管理”标签,就可以看到列表数据了:

这样我们就完成了一个ASP.NET MVC+EF实现异步增删改查的方法了。 最终项目结构:

 

GitHub代码地址: [email protected]:JiangXiaoLiang1988/TaskAsync.git

Guess you like

Origin www.cnblogs.com/dotnet261010/p/12348289.html