功能实现
我们以学生为例,实现增删改查功能。
1、搭建UI层
我们这里使用ASP.NET MVC作为界面层显示数据,首先创建一个解决方案,然后添加一个MVC项目,命名为TaskAsync.UI,创建后的项目结构如下图所示:
2、添加实体类
我们把实体类放在单独的类库里面,新建一个类型项目,命名为TaskAsync.Model,里面有一个Student类,Student类代码如下:
namespace TaskAsync.Model { ////// 学生类 /// public class Student { ////// 主键 /// public int Id { get; set; } ////// 姓名 /// public string Name { get; set; } ////// 年龄 /// public int Age { get; set; } ////// 性别 /// public int Gender { get; set; } } }
3、添加服务接口层
我们把增删改查的方法定义在接口里面,新添加一个类型项目,命名为TaskAsync.IService,需要引用上面创建的实体类库。里面有一个IStudentService接口,接口代码如下:
using System.Collections.Generic; using System.Threading.Tasks; using TaskAsync.Model; namespace TaskAsync.IService { public interface IStudentService { ////// 增加的异步方法 /// /// ///Task AddPersonAsync(Student entity); /// /// 删除的异步方法 /// /// ///Task DeleteByIdAsync(int id); /// /// 获取所有数据 /// ///Task > GetAllAsync(); /// /// 根据Id获取单一值 /// /// ///Task GetStudentByIdAsync(int id); /// /// 更新的异步方法 /// /// ///Task UpdateAsync(Student entity); } }
所有的方法返回值都是Task
4、添加Entity Framework
我们使用EF作为ORM框架,把EF放在单独类库里面,命名为TaskAsync.Data。直接在NuGet里面安装:
安装完成以后,我们同样需要在创建的ASP.NET MVC程序里面EntityFramework,然后在外层的Web.config文件里面添加链接字符串:
注意:链接字符串里面的providerName不能省略,否则进行数据迁移的时候会报错。
我们在TaskAsync.Data项目里面添加数据上下文类,继承自父类的DbContext:
using System.Data.Entity; using TaskAsync.Model; namespace TaskAsync.Data { ////// 数据上下文类,继承自父类的DbContext /// public class AppDbContext:DbContext { ////// 通过创建连接,给父类的构造函数传递参数 /// 参数是连接字符串的名称 /// 表示使用连接字符串中名字为DbConnectionString的去连接数据库 /// public AppDbContext():base("name=DbConnectionString") { } ////// 重写OnModelCreating方法 /// /// protected override void OnModelCreating(DbModelBuilder modelBuilder) { // 配置生成的表名 modelBuilder.Entity().ToTable("T_Student"); base.OnModelCreating(modelBuilder); } public DbSet 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{ public Configuration() { AutomaticMigrationsEnabled = false; } protected override void Seed(TaskAsync.Data.AppDbContext context) { List list = new List () { 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 { ////// 新增 方法标注为async /// /// ///public async Task AddPersonAsync(Student entity) { using (AppDbContext dbContext = new AppDbContext()) { dbContext.Students.Add(entity); // 调用异步方法 int count = await dbContext.SaveChangesAsync(); return count; } } /// /// 删除 /// /// ///public async Task 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 > GetAllAsync() { List list = await Task.Run >(() => { using (AppDbContext dbContext = new AppDbContext()) { return dbContext.Students.ToList(); } }); return list; } public async Task
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 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 TaskIndex() { return View(await service.GetAllAsync()); } // GET: Student/Details/5 public async Task 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 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 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 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 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 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视图文件,添加学生管理的一个标签:
@ViewBag.Title - 我的 ASP.NET 应用程序 @Styles.Render("~/Content/css") @Scripts.Render("~/bundles/modernizr")@RenderBody()@Scripts.Render("~/bundles/jquery") @Scripts.Render("~/bundles/bootstrap") @RenderSection("scripts", required: false)
运行程序,点击“学生管理”标签,就可以看到列表数据了:
这样我们就完成了一个ASP.NET MVC+EF实现异步增删改查的方法了。 最终项目结构:
GitHub代码地址:https://github.com/jxl1024/TaskAsync。
到此这篇关于ASP.NET MVC+EF实现异步增删改查的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持脚本之家。