<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      MVC3+EF4.1學習系列(八)-----利用Repository and Unit of Work重構項目

      文章索引和簡介

      項目最基礎的東西已經結束了,但是現在我們的項目還不健全  不利于測試 重復性代碼多   層與層之間耦合性高  不利于擴展等問題.今天的這章 主要就是解決這些問題的。再解決這些問題時,自己也產生了很多疑問,理解的也并不是很透徹 ,希望我的疑問能在這里得到解答~~

      一.模式介紹

      1.Repository

      在《企業架構模式》中,通過用來訪問領域對象的一個類似集合的接口,在領域與數據映射層之間進行協調。還有請大家參考這個  P OF EAA詳細介紹

      然后說下我對這個的感覺和疑問   怎么都覺得這個Repository就是以前的dao(dal)層~~  不過就是通過接口 泛型 與ORM結合 實現了更好的復用 不知道對不~~

      2.Unit of Work

      先上介紹  Unit Of Work 定義和解釋  。主要是解決當有多個操作時,數據的變更 存儲 以及事務的處理等 。unit of work是一個記錄所有對象模型修改過的信息,在提交的時候,一次性修改,并把結果同步到數據庫。 其實我們可以發現 DbContext 已經具備了這樣的功能~~ 很大程度實現了Unit of work~  因為我們savechange()

      時 才提交數據的

      3.整體概述

      運用Repository 和Unit of Work 在 數據層  和業務邏輯層之間 再創建一個抽象層 。它將幫我們隔離變化,并且更利于測試.

      下面借用下原文的圖 說明下使用Repository 和Unit of Work和不使用的區別

      二.改造開始

      讓我們回到最早的學生控制器上 忘了講啥的朋友可以看下這節-------學生控制器    我們把

      private SchoolContext db = new SchoolContext();

      寫在了每個控制器里面  聲明周期與控制器完全耦合在了一起

      1.創建學生資源庫接口

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Web;
      using ContosoUniversity.Models;

      namespace ContosoUniversity.DAL
      {
      public interface IStudentRepository : IDisposable
      {
      IEnumerable
      <Student> GetStudents();
      Student GetStudentByID(
      int studentId);
      void InsertStudent(Student student);
      void DeleteStudent(int studentID);
      void UpdateStudent(Student student);
      void Save();
      }
      }

      2.實現接口

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Data;
      using ContosoUniversity.Models;

      namespace ContosoUniversity.DAL
      {
      public class StudentRepository : IStudentRepository, IDisposable
      {
      private SchoolContext context;

      public StudentRepository(SchoolContext context)
      {
      this.context = context;
      }

      public IEnumerable<Student> GetStudents()
      {
      return context.Students.ToList();
      }

      public Student GetStudentByID(int id)
      {
      return context.Students.Find(id);
      }

      public void InsertStudent(Student student)
      {
      context.Students.Add(student);
      }

      public void DeleteStudent(int studentID)
      {
      Student student
      = context.Students.Find(studentID);
      context.Students.Remove(student);
      }

      public void UpdateStudent(Student student)
      {
      context.Entry(student).State
      = EntityState.Modified;
      }

      public void Save()
      {
      context.SaveChanges();
      }

      private bool disposed = false;

      protected virtual void Dispose(bool disposing)
      {
      if (!this.disposed)
      {
      if (disposing)
      {
      context.Dispose();
      }
      }
      this.disposed = true;
      }

      public void Dispose()
      {
      Dispose(
      true);
      GC.SuppressFinalize(
      this);
      }
      }
      }

      3.改造學生控制器

      View Code
      using System;
      using System.Collections.Generic;
      using System.Data;
      using System.Data.Entity;
      using System.Linq;
      using System.Web;
      using System.Web.Mvc;
      using ContosoUniversity.Models;
      using ContosoUniversity.DAL;
      using PagedList;

      namespace ContosoUniversity.Controllers
      {
      public class StudentController : Controller
      {
      private IStudentRepository studentRepository;


      public StudentController()
      {
      this.studentRepository = new StudentRepository(new SchoolContext());
      }

      public StudentController(IStudentRepository studentRepository)
      {
      this.studentRepository = studentRepository;
      }


      //
      // GET: /Student/

      public ViewResult Index(string sortOrder, string currentFilter, string searchString, int? page)
      {
      ViewBag.CurrentSort
      = sortOrder;
      ViewBag.NameSortParm
      = String.IsNullOrEmpty(sortOrder) ? "Name desc" : "";
      ViewBag.DateSortParm
      = sortOrder == "Date" ? "Date desc" : "Date";

      if (Request.HttpMethod == "GET")
      {
      searchString
      = currentFilter;
      }
      else
      {
      page
      = 1;
      }
      ViewBag.CurrentFilter
      = searchString;

      var students
      = from s in studentRepository.GetStudents()
      select s;
      if (!String.IsNullOrEmpty(searchString))
      {
      students
      = students.Where(s => s.LastName.ToUpper().Contains(searchString.ToUpper())
      || s.FirstMidName.ToUpper().Contains(searchString.ToUpper()));
      }
      switch (sortOrder)
      {
      case "Name desc":
      students
      = students.OrderByDescending(s => s.LastName);
      break;
      case "Date":
      students
      = students.OrderBy(s => s.EnrollmentDate);
      break;
      case "Date desc":
      students
      = students.OrderByDescending(s => s.EnrollmentDate);
      break;
      default:
      students
      = students.OrderBy(s => s.LastName);
      break;
      }

      int pageSize = 3;
      int pageIndex = (page ?? 1) - 1;
      return View(students.ToPagedList(pageIndex, pageSize));
      }


      //
      // GET: /Student/Details/5

      public ViewResult Details(int id)
      {
      Student student
      = studentRepository.GetStudentByID(id);
      return View(student);
      }

      //
      // GET: /Student/Create

      public ActionResult Create()
      {
      return View();
      }

      //
      // POST: /Student/Create

      [HttpPost]
      public ActionResult Create(Student student)
      {
      try
      {
      if (ModelState.IsValid)
      {
      studentRepository.InsertStudent(student);
      studentRepository.Save();
      return RedirectToAction("Index");
      }
      }
      catch (DataException)
      {
      //Log the error (add a variable name after DataException)
      ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
      }
      return View(student);
      }

      //
      // GET: /Student/Edit/5

      public ActionResult Edit(int id)
      {
      Student student
      = studentRepository.GetStudentByID(id);
      return View(student);
      }

      //
      // POST: /Student/Edit/5

      [HttpPost]
      public ActionResult Edit(Student student)
      {
      try
      {
      if (ModelState.IsValid)
      {
      studentRepository.UpdateStudent(student);
      studentRepository.Save();
      return RedirectToAction("Index");
      }
      }
      catch (DataException)
      {
      //Log the error (add a variable name after DataException)
      ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
      }
      return View(student);
      }

      //
      // GET: /Student/Delete/5

      public ActionResult Delete(int id, bool? saveChangesError)
      {
      if (saveChangesError.GetValueOrDefault())
      {
      ViewBag.ErrorMessage
      = "Unable to save changes. Try again, and if the problem persists see your system administrator.";
      }
      Student student
      = studentRepository.GetStudentByID(id);
      return View(student);
      }


      //
      // POST: /Student/Delete/5

      [HttpPost, ActionName(
      "Delete")]
      public ActionResult DeleteConfirmed(int id)
      {
      try
      {
      Student student
      = studentRepository.GetStudentByID(id);
      studentRepository.DeleteStudent(id);
      studentRepository.Save();
      }
      catch (DataException)
      {
      //Log the error (add a variable name after DataException)
      return RedirectToAction("Delete",
      new System.Web.Routing.RouteValueDictionary {
      {
      "id", id },
      {
      "saveChangesError", true } });
      }
      return RedirectToAction("Index");
      }

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

      通過上面的操作  現在我們的控制器  針對的是一個接口 而不再是直接通過dbContext   當然 如果我們這里使用IOC容器  將能實現更好的解耦 大家可以看下

      桀驁的靈魂的 這篇文章

      4.改造后出現的問題

      1.我們本來在控制器里實現的dbContext,  現在這個被放在了Repository里   因為項目會有多個Repository  所以會有多個dbContext!  這是個時候 當我們有

      一個復雜的邏輯   要用到多個Repository時  比如 我隨便說個例子~~  比如 添加個訂單 更新個詳細訂單 再刪除個客戶 假設這一系列的邏輯 是在一起的  這里就會用到三個 Repository    我們要調用不同的Repository  里的 SAVE()    這時 我們就要做多次提交 而且不再是統一的事務了  效率 完整性 都大大的下降了。反而失去了

      dbContext 自帶 Unit of Work的好處~~   沒關系  后面我們會再實現Unit of Work 來改造這個問題

      2.第二個問題 也是個很嚴重的問題 我們以前的時候  再查找學生  搜索 排序 以及分頁時  是這樣的

      var students = from s in context.Students
      select s;
      if (!String.IsNullOrEmpty(searchString))
      {
      students
      = students.Where(s => s.LastName.ToUpper().Contains(searchString.ToUpper())
      || s.FirstMidName.ToUpper().Contains(searchString.ToUpper()));
      }

      而現在變成了

      var students = from s in studentRepository.GetStudents()
      select s;

      這有個很嚴重的問題 以前是 IQueryable 而現在的是  IEnumerable  變成了數據直接全部查找出來  所以再這里 我覺得Repository的查找 應該是返回IQueryable

      而不是 IEnumerable 

      要不然 就出現了我最早在文中的疑問  這不就是普通的CRUD 一個普通的數據訪問層而已   

      Repository用法我覺得應該是 返回IQueryable 參數的接受應該是一個表達式樹  不知道大家是否認同?希望大家幫我解決下疑惑 謝謝~

      再下面的 公共泛型 Repository 會體現這個

      三.創建一個公共的Repository

      看看我們上面的學生Repository   如果我們再寫 課程 院系 等等 這些代碼 會非常類似  所以我們利用泛型注入 來實現復用  這里應該實現一個泛型接口 和泛型類

      但是原文沒有實現接口~ 只有個類

      讓我來看下這個類

      namespace ContosoUniversity.DAL
      {
      public class GenericRepository<TEntity> where TEntity : class
      {
      internal SchoolContext context;
      internal DbSet<TEntity> dbSet;

      public GenericRepository(SchoolContext context)
      {
      this.context = context;
      this.dbSet = context.Set<TEntity>();
      }

      public virtual IEnumerable<TEntity> Get(
      Expression
      <Func<TEntity, bool>> filter = null,
      Func
      <IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
      string includeProperties = "")
      {
      IQueryable
      <TEntity> query = dbSet;

      if (filter != null)
      {
      query
      = query.Where(filter);
      }

      foreach (var includeProperty in includeProperties.Split
      (
      new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
      {
      query
      = query.Include(includeProperty);
      }

      if (orderBy != null)
      {
      return orderBy(query).ToList();
      }
      else
      {
      return query.ToList();
      }
      }

      public virtual TEntity GetByID(object id)
      {
      return dbSet.Find(id);
      }

      public virtual void Insert(TEntity entity)
      {
      dbSet.Add(entity);
      }

      public virtual void Delete(object id)
      {
      TEntity entityToDelete
      = dbSet.Find(id);
      Delete(entityToDelete);
      }

      public virtual void Delete(TEntity entityToDelete)
      {
      if (context.Entry(entityToDelete).State == EntityState.Detached)
      {
      dbSet.Attach(entityToDelete);
      }
      dbSet.Remove(entityToDelete);
      }

      public virtual void Update(TEntity entityToUpdate)
      {
      dbSet.Attach(entityToUpdate);
      context.Entry(entityToUpdate).State
      = EntityState.Modified;
      }
      }
      }

      這里重點講這個方法

      public virtual IEnumerable<TEntity> Get(
      Expression
      <Func<TEntity, bool>> filter = null,
      Func
      <IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
      string includeProperties = "")
      {
      IQueryable
      <TEntity> query = dbSet;

      if (filter != null)
      {
      query
      = query.Where(filter);
      }

      foreach (var includeProperty in includeProperties.Split
      (
      new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
      {
      query
      = query.Include(includeProperty);
      }

      if (orderBy != null)
      {
      return orderBy(query).ToList();
      }
      else
      {
      return query.ToList();
      }
      }

      還是如上面所說 我覺得這里應該返回的是 IQueryable 所以我覺得應該 去掉最后的 .ToList  并且返回IQueryable 

      然后 來看這個方法  第一個接受一個表達式樹   其實就是過濾條件  第二個 是個委托 主要是用來排序的   第三個接受要貪婪加載哪些導航屬性 可以用逗號隔開

      并且 這里利用了下4.0的功能 可以給參數個默認值  都是空  怎么用這個方法 后面會寫的有~~

      還有個說的地方 以前我沒有提到過   這里稍帶的說下

           public virtual void Delete(TEntity entityToDelete)
      {
      if (context.Entry(entityToDelete).State == EntityState.Detached)
      {
      dbSet.Attach(entityToDelete);
      }
      dbSet.Remove(entityToDelete);
      }

      這個 dbSet.Attach(entityToDelete);  表示將對象添加到數據庫上下文中   受dbcontext管理  這里我有個小疑問  不加這個判斷 是否也可以 加這個的好處是?

      四.創建 Unit of Work Class

      創建這個類的主要目的  就是為了確保 多個Repository可以共享一個 database context  讓我們看下這個類

      namespace ContosoUniversity.DAL
      {
      public class UnitOfWork : IDisposable
      {
      private SchoolContext context = new SchoolContext();
      private GenericRepository<Department> departmentRepository;
      private GenericRepository<Course> courseRepository;

      public GenericRepository<Department> DepartmentRepository
      {
      get
      {

      if (this.departmentRepository == null)
      {
      this.departmentRepository = new GenericRepository<Department>(context);
      }
      return departmentRepository;
      }
      }

      public GenericRepository<Course> CourseRepository
      {
      get
      {

      if (this.courseRepository == null)
      {
      this.courseRepository = new GenericRepository<Course>(context);
      }
      return courseRepository;
      }
      }

      public void Save()
      {
      context.SaveChanges();
      }

      private bool disposed = false;

      protected virtual void Dispose(bool disposing)
      {
      if (!this.disposed)
      {
      if (disposing)
      {
      context.Dispose();
      }
      }
      this.disposed = true;
      }

      public void Dispose()
      {
      Dispose(
      true);
      GC.SuppressFinalize(
      this);
      }
      }
      }

      把想讓unit of work 幫你整體控制的類寫到里面 這里 我們只寫了兩個

      private SchoolContext context = new SchoolContext();
      private GenericRepository<Department> departmentRepository;
      private GenericRepository<Course> courseRepository;

      實現只讀屬性

      public GenericRepository<Department> DepartmentRepository
      {
      get
      {

      if (this.departmentRepository == null)
      {
      this.departmentRepository = new GenericRepository<Department>(context);
      }
      return departmentRepository;
      }
      }

      最后是保存和資源的釋放

      好 現在看下怎么用這個~

      五.改變課程控制器

      原文控制器代碼
      namespace ContosoUniversity.Controllers
      {
      public class CourseController : Controller
      {
      private UnitOfWork unitOfWork = new UnitOfWork();

      //
      // GET: /Course/

      public ViewResult Index()
      {
      var courses
      = unitOfWork.CourseRepository.Get(includeProperties: "Department");
      return View(courses.ToList());
      }

      //
      // GET: /Course/Details/5

      public ViewResult Details(int id)
      {
      Course course
      = unitOfWork.CourseRepository.GetByID(id);
      return View(course);
      }

      //
      // GET: /Course/Create

      public ActionResult Create()
      {
      PopulateDepartmentsDropDownList();
      return View();
      }

      [HttpPost]
      public ActionResult Create(Course course)
      {
      try
      {
      if (ModelState.IsValid)
      {
      unitOfWork.CourseRepository.Insert(course);
      unitOfWork.Save();
      return RedirectToAction("Index");
      }
      }
      catch (DataException)
      {
      //Log the error (add a variable name after DataException)
      ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
      }
      PopulateDepartmentsDropDownList(course.DepartmentID);
      return View(course);
      }

      public ActionResult Edit(int id)
      {
      Course course
      = unitOfWork.CourseRepository.GetByID(id);
      PopulateDepartmentsDropDownList(course.DepartmentID);
      return View(course);
      }

      [HttpPost]
      public ActionResult Edit(Course course)
      {
      try
      {
      if (ModelState.IsValid)
      {
      unitOfWork.CourseRepository.Update(course);
      unitOfWork.Save();
      return RedirectToAction("Index");
      }
      }
      catch (DataException)
      {
      //Log the error (add a variable name after DataException)
      ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
      }
      PopulateDepartmentsDropDownList(course.DepartmentID);
      return View(course);
      }

      private void PopulateDepartmentsDropDownList(object selectedDepartment = null)
      {
      var departmentsQuery
      = unitOfWork.DepartmentRepository.Get(
      orderBy: q
      => q.OrderBy(d => d.Name));
      ViewBag.DepartmentID
      = new SelectList(departmentsQuery, "DepartmentID", "Name", selectedDepartment);
      }

      //
      // GET: /Course/Delete/5

      public ActionResult Delete(int id)
      {
      Course course
      = unitOfWork.CourseRepository.GetByID(id);
      return View(course);
      }

      //
      // POST: /Course/Delete/5

      [HttpPost, ActionName(
      "Delete")]
      public ActionResult DeleteConfirmed(int id)
      {
      Course course
      = unitOfWork.CourseRepository.GetByID(id);
      unitOfWork.CourseRepository.Delete(id);
      unitOfWork.Save();
      return RedirectToAction("Index");
      }

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

      原文的這個demo 并沒有很好的體現出 使用 unit of work 的好處  因為他的這個例子沒有出現一個邏輯用到多個資源庫的  希望大家明白這點~~ 等以后的文章

      我會寫個完整的demo  來說明這點 這里大家先看下 明白怎么回事就行~

      六.EF+MVC框架的疑問

      1.是否有必要實現 IUnitOfWork 接口?代碼大概這樣

      public interface IUnitOfWork

      {

      void Save();

      IStudentRepository StudentRepository {
      get; }

      }

      實現接口

      public class UnitOfWork : IUnitOfWork

      {

      private SchoolEntities context = new SchoolEntities();

      private IStudentRepository studentRepository;

      public IStudentRepository StudentRepository

      {

      get

      {

      if (this.studentRepository == null)

      {

      this.studentRepository = new StudentRepository(context);

      }

      return studentRepository;

      }

      }

      public void Save()

      {

      context.SaveChanges();

      }

      }

      控制器

      private IUnitOfWork unitOfWork;

      public StudentController () : this (new UnitOfWork())

      {

      }

      public StudentController (IUnitOfWork unitOfWork)

      {

      this.unitOfWork = unitOfWork;

      }

      2. 是否有必要再  加上一個 服務層 service  這個層 在 控制器和dal 之間   也就是 通過 unitofwork 調用的東西等 都寫在servie上  這樣控制器里的代碼會變得非常少, 個人覺得應該加上service層的,但是是否需要加Iservice 接口    加這個接口 能獲得哪些好處 ? 我一直覺得 只用 給數據訪問層 實現接口 就行  ~~

      3. 這里我們是用的unit of work 完成了事務的一致性  以前我是使用

      using (TransactionScope transaction = new TransactionScope()){
      ....

      transaction.Complete();
      }

      用這個來實現 事務一致性  不知道大家覺得 這個和 unit of work 比怎么樣? 我暫時還沒研究這個~     但是 小城歲月 對這個做了很好的介紹 感謝小城~ 大家可以參考他的這篇文章

      4. 我們的緩存 比如用的 mongodb 這個寫到哪層比較好呢?

      六.總結

      經過重構 代碼終于有些項目的樣子了~~   下節講講EF的其他一些功能 如 直接執行SQL語句,關閉跟蹤狀態這些~~

      posted on 2011-08-05 08:48  wlf  閱讀(22909)  評論(49)    收藏  舉報

      主站蜘蛛池模板: 无码激情亚洲一区| 免费超爽大片黄| 亚洲精品成人久久久| 日韩精品中文字幕亚洲| 欧美性猛交xxxx乱大交极品| 成人动漫综合网| 精品亚洲精品日韩精品| 国产精品成熟老女人| 久久影院午夜伦手机不四虎卡| 亚洲日本韩国欧美云霸高清| 天天看片视频免费观看| 国产精品久久久天天影视香蕉 | 18禁无遮挡啪啪无码网站破解版| 亚洲欧洲日产国码久在线| 樱花草在线社区www| 成人午夜在线观看日韩| 中文字幕一区二区三区麻豆| brazzers欧美巨大| 国产精品白浆无码流出| 99久re热视频这里只有精品6| 丰满少妇高潮在线播放不卡| 色综合久久一区二区三区| av中文字幕一区二区| 日本高清一区二区三| 九九热精彩视频在线免费| 亚洲另类激情专区小说图片| 女人腿张开让男人桶爽| 亚洲精品一区二区毛豆| 午夜精品视频在线看| 亚洲日本韩国欧美云霸高清| 国产一区二区不卡在线看| 亚洲国产精品特色大片观看完整版 | 高清欧美性猛交xxxx黑人猛交| 国产精品午夜福利小视频| 国产精品二区中文字幕 | 亚洲特黄色片一区二区三区| 精品在免费线中文字幕久久| 国产精品乱一区二区三区| 强奷漂亮人妻系列老师| 图木舒克市| 婷婷99视频精品全部在线观看|