May 28, 2014
10 mins read
Repository Pattern 是一個用來切割資料存取層和商業邏輯層的模式 針對資料的存取提供了基本的新增、修改、刪除、查詢等操作 返回的對象應該為IQueryable以供商業邏輯做更進一步的處理 這樣的好處是商業邏輯不直接處理資料的存取,方便之後抽換資料存取層,也方便單元測試 以下用一個簡單的留言版當例子透過ADO.NET和Entity Framework來存取資料 首先準備好留言版的資料庫,資料表就簡單的用GuestbookId和Message就好
namespace WebApplication1.Models { using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema;順便定義一個DbContext[Table("Guestbook")] public class Guestbook { [Key] public int GuestbookId { get; set; } public string Message { get; set; } }
}
namespace WebApplication1.Models { using System.Data.Entity; public class GuestbookContext : DbContext { public DbSet<Guestbook> Guestbook { get; set; } } }
定義一個IGuestbookRepository介面
namespace WebApplication1.Repositories { using System; using System.Linq; using WebApplication1.Models; public interface IGuestbookRepository : IDisposable { IQueryable<Guestbook> GetAll(); Guestbook Find(int id); void Add(Guestbook model); void Edit(Guestbook model); void Delete(int id); } }
透過EntityFramework實作一個Repository
namespace WebApplication1.Repositories { using System; using System.Data.Entity; using System.Linq; using WebApplication1.Models; public class EFGuestbookRepository : IGuestbookRepository { private bool disposed = false; private GuestbookContext db; public EFGuestbookRepository() { this.db = new GuestbookContext(); } public IQueryable<Guestbook> GetAll() { return this.db.Guestbook; } public Models.Guestbook Find(int id) { return this.db.Guestbook.Find(id); } public void Add(Guestbook model) { this.db.Guestbook.Add(model); this.db.SaveChanges(); } public void Edit(Guestbook model) { this.db.Entry(model).State = EntityState.Modified; this.db.SaveChanges(); } public void Delete(int id) { var model = new Guestbook { GuestbookId = id }; this.db.Entry(model).State = EntityState.Deleted; this.db.SaveChanges(); } public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (disposed) { return; } this.disposed = true; if (disposing) { this.db.Dispose(); } } } }
透過ADO.Net實作一個Repository
namespace WebApplication1.Repositories { using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Data.SqlClient; using System.Linq; using WebApplication1.Models; public class ADONetGuestbookRepository : IGuestbookRepository { private bool disposed = false; private SqlConnection objConn; private SqlCommand objCmd; public ADONetGuestbookRepository() { string strConn = ConfigurationManager.ConnectionStrings["GuestbookContext"].ConnectionString; objConn = new SqlConnection(strConn); objConn.Open(); objCmd = new SqlCommand(); objCmd.Connection = objConn; } public IQueryable<Guestbook> GetAll() { List<Guestbook> list = new List<Guestbook>(); objCmd.CommandText = "SELECT * FROM Guestbook"; using (SqlDataReader objDtr = objCmd.ExecuteReader()) { while (objDtr.Read()) { Guestbook model = new Guestbook() { GuestbookId = Convert.ToInt32(objDtr["GuestbookId"]), Message = objDtr["Message"].ToString(), }; list.Add(model); } } return list.AsQueryable(); } public Models.Guestbook Find(int id) { Guestbook model = new Guestbook(); objCmd.CommandText = "SELECT * FROM Guestbook WHERE GuestbookId = @GuestbookId"; objCmd.Parameters.AddWithValue("@GuestbookId", id); using (SqlDataReader objDtr = objCmd.ExecuteReader()) { if (objDtr.Read()) { model.GuestbookId = Convert.ToInt32(objDtr["GuestbookId"]); model.Message = objDtr["Message"].ToString(); } } return model; } public void Add(Guestbook model) { objCmd.CommandText = "INSERT INTO Guestbook(Message) VALUES(@Message)"; objCmd.Parameters.AddWithValue("@Message", model.Message); objCmd.ExecuteNonQuery(); } public void Edit(Guestbook model) { objCmd.CommandText = "UPDATE Guestbook SET Message = @Message WHERE GuestbookId = @GuestbookId"; objCmd.Parameters.AddWithValue("@GuestbookId", model.GuestbookId); objCmd.Parameters.AddWithValue("@Message", model.Message); objCmd.ExecuteNonQuery(); } public void Delete(int id) { objCmd.CommandText = "DELETE FROM Guestbook WHERE GuestbookId = @GuestbookId"; objCmd.Parameters.AddWithValue("@GuestbookId", id); objCmd.ExecuteNonQuery(); } public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (this.disposed) { return; } this.disposed = true; if (disposing) { if (objConn.State != ConnectionState.Closed) { objConn.Close(); } this.objConn.Dispose(); this.objCmd.Dispose(); } } } }
透過Scaffold產生Controller和View
產生的Controller裡面是直接透過Entity Framework存取資料
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity; using System.Linq; using System.Net; using System.Web; using System.Web.Mvc; using WebApplication1.Models; namespace WebApplication1.Controllers { public class GuestbookController : Controller { private GuestbookContext db = new GuestbookContext(); // GET: Guestbook public ActionResult Index() { return View(db.Guestbook.ToList()); } // GET: Guestbook/Details/5 public ActionResult Details(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Guestbook guestbook = db.Guestbook.Find(id); if (guestbook == null) { return HttpNotFound(); } return View(guestbook); } // GET: Guestbook/Create public ActionResult Create() { return View(); } // POST: Guestbook/Create // 若要免於過量張貼攻擊,請啟用想要繫結的特定屬性,如需 // 詳細資訊,請參閱 http://go.microsoft.com/fwlink/?LinkId=317598。 [HttpPost] [ValidateAntiForgeryToken] public ActionResult Create([Bind(Include = "GuestbookId,Message")] Guestbook guestbook) { if (ModelState.IsValid) { db.Guestbook.Add(guestbook); db.SaveChanges(); return RedirectToAction("Index"); } return View(guestbook); } // GET: Guestbook/Edit/5 public ActionResult Edit(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Guestbook guestbook = db.Guestbook.Find(id); if (guestbook == null) { return HttpNotFound(); } return View(guestbook); } // POST: Guestbook/Edit/5 // 若要免於過量張貼攻擊,請啟用想要繫結的特定屬性,如需 // 詳細資訊,請參閱 http://go.microsoft.com/fwlink/?LinkId=317598。 [HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit([Bind(Include = "GuestbookId,Message")] Guestbook guestbook) { if (ModelState.IsValid) { db.Entry(guestbook).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(guestbook); } // GET: Guestbook/Delete/5 public ActionResult Delete(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Guestbook guestbook = db.Guestbook.Find(id); if (guestbook == null) { return HttpNotFound(); } return View(guestbook); } // POST: Guestbook/Delete/5 [HttpPost, ActionName("Delete")] [ValidateAntiForgeryToken] public ActionResult DeleteConfirmed(int id) { Guestbook guestbook = db.Guestbook.Find(id); db.Guestbook.Remove(guestbook); db.SaveChanges(); return RedirectToAction("Index"); } protected override void Dispose(bool disposing) { if (disposing) { db.Dispose(); } base.Dispose(disposing); } } }做一點調整改用剛定義的IGuestbookRepository介面來存取資料
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity; using System.Linq; using System.Net; using System.Web; using System.Web.Mvc; using WebApplication1.Models; using WebApplication1.Repositories; namespace WebApplication1.Controllers { public class GuestbookController : Controller { private IGuestbookRepository db; public GuestbookController() { this.db = new EFGuestbookRepository(); } // GET: Guestbook public ActionResult Index() { return View(this.db.GetAll()); } // GET: Guestbook/Details/5 public ActionResult Details(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Guestbook guestbook = this.db.Find(id.Value); if (guestbook == null) { return HttpNotFound(); } return View(guestbook); } // GET: Guestbook/Create public ActionResult Create() { return View(); } // POST: Guestbook/Create // 若要免於過量張貼攻擊,請啟用想要繫結的特定屬性,如需 // 詳細資訊,請參閱 http://go.microsoft.com/fwlink/?LinkId=317598。 [HttpPost] [ValidateAntiForgeryToken] public ActionResult Create([Bind(Include = "GuestbookId,Message")] Guestbook guestbook) { if (ModelState.IsValid) { this.db.Add(guestbook); return RedirectToAction("Index"); } return View(guestbook); } // GET: Guestbook/Edit/5 public ActionResult Edit(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Guestbook guestbook = this.db.Find(id.Value); if (guestbook == null) { return HttpNotFound(); } return View(guestbook); } // POST: Guestbook/Edit/5 // 若要免於過量張貼攻擊,請啟用想要繫結的特定屬性,如需 // 詳細資訊,請參閱 http://go.microsoft.com/fwlink/?LinkId=317598。 [HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit([Bind(Include = "GuestbookId,Message")] Guestbook guestbook) { if (ModelState.IsValid) { this.db.Edit(guestbook); return RedirectToAction("Index"); } return View(guestbook); } // GET: Guestbook/Delete/5 public ActionResult Delete(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Guestbook guestbook = this.db.Find(id.Value); if (guestbook == null) { return HttpNotFound(); } return View(guestbook); } // POST: Guestbook/Delete/5 [HttpPost, ActionName("Delete")] [ValidateAntiForgeryToken] public ActionResult DeleteConfirmed(int id) { this.db.Delete(id); return RedirectToAction("Index"); } protected override void Dispose(bool disposing) { if (disposing) { db.Dispose(); } base.Dispose(disposing); } } }要切換存取資料的Repository只要在建構式中切換建立的類別就行了
public GuestbookController() { // this.db = new EFGuestbookRepository(); this.db = new ADONetGuestbookRepository(); }
透過DI的方式注入介面切換就更靈活了
public GuestbookController(IGuestbookRepository repository) { this.db = repository; }
Sharing is caring!