使用实体框架、代码优先和 CRUD 操作的存储库模式

Posted

技术标签:

【中文标题】使用实体框架、代码优先和 CRUD 操作的存储库模式【英文标题】:Repository Pattern using Entity Framework, code first and CRUD operations 【发布时间】:2014-10-25 20:46:37 【问题描述】:

我正在尝试对如何正确实施存储库模式有一个实际的了解。我在我的 MVC Web 应用程序中创建了一个名为Employees 的模型类,我创建了一个上下文类和一个连接字符串来生成一个数据库。我还使用实体框架创建了一个具有读/写操作的控制器,它带来了一些 CRUD 操作,如更新、删除等。

如果我正确理解了存储库模式,我应该将所有数据访问逻辑放在存储库中。我也相信我需要为上下文类创建一个 IRepository 接口来继承。

在我的控制器中,我有这些基本的 CRUD 操作。就我而言,是否应该将这些操作方法中的所有逻辑移至我的存储库类?

控制器:

public class EmployeeController : Controller

    private _dbCrudApplicationContext db = new _dbCrudApplicationContext();

    // GET: Employee
    public ActionResult Index()
    
        return View(db.Employees.ToList());
    

    // GET: Employee/Details/5
    public ActionResult Details(int? id)
    
        if (id == null)
        
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        
        Employee employee = db.Employees.Find(id);
        if (employee == null)
        
            return HttpNotFound();
        
        return View(employee);
    

    // GET: Employee/Create
    public ActionResult Create()
    
        return View();
    

    // POST: Employee/Create
    // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
    // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "Id,FirstName,LastName,EmployeeNumber,Department,HasValidEmployeeCertificate")] Employee employee)
    
        if (ModelState.IsValid)
        
            db.Employees.Add(employee);
            db.SaveChanges();
            return RedirectToAction("Index");
        

        return View(employee);
    

    // GET: Employee/Edit/5
    public ActionResult Edit(int? id)
    
        if (id == null)
        
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        
        Employee employee = db.Employees.Find(id);
        if (employee == null)
        
            return HttpNotFound();
        
        return View(employee);
    

    // POST: Employee/Edit/5
    // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
    // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit([Bind(Include = "Id,FirstName,LastName,EmployeeNumber,Department,HasValidEmployeeCertificate")] Employee employee)
    
        if (ModelState.IsValid)
        
            db.Entry(employee).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        
        return View(employee);
    

    // GET: Employee/Delete/5
    public ActionResult Delete(int? id)
    
        if (id == null)
        
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        
        Employee employee = db.Employees.Find(id);
        if (employee == null)
        
            return HttpNotFound();
        
        return View(employee);
    

    // POST: Employee/Delete/5
    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public ActionResult DeleteConfirmed(int id)
    
        Employee employee = db.Employees.Find(id);
        db.Employees.Remove(employee);
        db.SaveChanges();
        return RedirectToAction("Index");
    

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

我已经开始将“索引”方法添加到存储库,但我不确定如何实现其他方法,因为它们更复杂。我应该在 Controller 的操作方法中移动所有逻辑还是只移动部分代码?

存储库:

public class CustomerRepository : _dbCrudApplicationContext

    _dbCrudApplicationContext db = new _dbCrudApplicationContext();


    public List<Employee> GetAllEmployees()
    
        return db.Employees.ToList();    
    

【问题讨论】:

请在此处查看我的答案:programmers.stackexchange.com/questions/180851/…。实体框架排除了使用存储库模式。这根本没有必要。您在这里要做的只是让您的应用程序更难使用。 【参考方案1】:

存储库不应尝试扩展模型上下文,而应使用此上下文执行某些操作。存储库定义为

存储库在域和数据映射层之间进行中介,就像内存中的域对象集合一样。客户端对象以声明方式构造查询规范,并将它们提交给 Repository 以获得满意。对象可以添加到 Repository 中,也可以从 Repository 中删除,就像从简单的对象集合中一样,Repository 封装的映射代码将在后台执行相应的操作

界面风格背后的主要原因是允许进行单元测试。

在您的情况下,存储库可能看起来像

public interface ICustomerRepository

   public List<Employee> GetAllEmployees();


public class CustomerRepository : ICustomerRepository

   private _dbCrudApplicationContext db;

   public CustomerRepository(_dbCrudApplicationContext context)
   
     db = context;
   

   public List<Employee> GetAllEmployees()
   
      return db.Employees.ToList();
   

完成后的存储库应包含要在模型上执行的所有操作。这些将需要从 MVC 视图迁移。

更多详情请见http://blog.gauffin.org/2013/01/repository-pattern-done-right/。

【讨论】:

以上是关于使用实体框架、代码优先和 CRUD 操作的存储库模式的主要内容,如果未能解决你的问题,请参考以下文章

代码优先实体框架或 NHibernate

带有实体框架的 CRUD WEB API

在实体框架中使用存储过程(代码优先)

如何在实体框架中定义存储过程(代码优先)?

具有实体框架 4.1 和父/子关系的存储库模式

如何从实体框架中的存储过程中获取结果+数据库优先