什么是IRepository以及它用于什么?

Sev*_*vki 36 c# vb.net asp.net-mvc

什么是IRepository?为什么使用它,简短而简单的例子不会受到伤害.

awr*_*ley 47

MVC促进了关注点的分离,但这并不止于MVC级别.

数据访问本身就是一个问题.它应该在MVC的M位,即模型中完成.你如何构建你的模型取决于你,但人们通常会遵循久经考验的模式(为什么重新发明轮子?).存储库模式是当前的标准.然而,不要指望一个简单的公式,因为变化与开发人员一样多.

IRepository只是您创建的接口(它不是MVC或ASP.NET或.NET的一部分).它允许您将存储库与实际实现"分离".解耦很好,因为它意味着你的代码...:

  1. 您的代码更可重用.这简直太好了.
  2. 您的代码可以使用Inversion of Control(或依赖注入).这样可以很好地保持您的关注点.它特别好,因为这允许单元测试......
  3. 您的代码可以进行单元测试.这在具有复杂算法的大型项目中尤其有用.它无处不在,因为它增加了您对所使用技术的理解以及您尝试在软件中建模的域.
  4. 您的代码将围绕最佳实践构建,遵循通用模式.这很好,因为它使维护更容易.

因此,在卖给你脱钩之后,你的问题的答案是IRepository是你创建的一个接口,并且你使你的存储库继承.它为您提供了可靠的类层次结构.

我通常使用通用的IRepository.即:

IRepository

在哪里,Tentity就是一个实体.我使用的代码是:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Wingspan.Web.Mvc
{
    public interface IRepository<TEntity> where TEntity : class
    {
        List<TEntity> FetchAll();
        IQueryable<TEntity> Query {get;}
        void Add(TEntity entity);
        void Delete(TEntity entity);
        void Save();
    }
}
Run Code Online (Sandbox Code Playgroud)

该接口的具体实现是:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;

using Wingspan.Web.Mvc;

namespace ES.eLearning.Domain
{
    public class SqlRepository<T> : IRepository<T> where T : class
    {
        DataContext db;
        public SqlRepository(DataContext db)
        {
            this.db = db;
        }

        #region IRepository<T> Members

        public IQueryable<T> Query
        {
            get { return db.GetTable<T>(); }
        }

        public List<T> FetchAll()
        {
            return Query.ToList();
        }

        public void Add(T entity)
        {
            db.GetTable<T>().InsertOnSubmit(entity);
        }

        public void Delete(T entity)
        {
            db.GetTable<T>().DeleteOnSubmit(entity);
        }

        public void Save()
        {
            db.SubmitChanges();
        }

        #endregion
    }
}
Run Code Online (Sandbox Code Playgroud)

这允许我写:

SqlRepository<UserCourse> UserCoursesRepository = new SqlRepository<UserCourse>(db);
Run Code Online (Sandbox Code Playgroud)

其中db是一个注入到服务中的DataContext实例.

使用UserCoursesRepository,我现在可以在我的Service类中编写方法,如:

public void DeleteUserCourse(int courseId)
        {
            var uc = (UserCoursesRepository.Query.Where(x => x.IdUser == UserId && x.IdCourse == courseId)).Single();
            UserCoursesRepository.Delete(uc);
            UserCoursesRepository.Save();
        }
Run Code Online (Sandbox Code Playgroud)

现在在我的控制器中,我可以写:

MyService.DeleteUserCourse(5);
MyService.Save();
Run Code Online (Sandbox Code Playgroud)

即,您的应用程序的开发变得更像是一个装配线,导致一个非常简单的控制器.装配线的每一部分都可以独立于其他任何部分进行测试,因此虫子被扼杀在萌芽状态.

如果这是一个漫长而笨拙的答案,那是因为真正的答案是:

购买Steven Sanderson的书Pro ASP.NET MVC 2 Framework并学习在MVC中思考.

  • 上述设计的缺陷:使用单个实体而不使用工作单元模式.在现实世界中,您需要在一个事务中使用多个实体,并且应该在工作单元的末尾调用SaveChanges方法,而不是在存储库类中调用. - 不使用UOW会导致多次往返数据库,而不是每次只使用一个连接. (4认同)
  • @VahidN:很公平,但是如果你打击某人问工作单位的"什么是IRepository",你就会失去它们.这些评论文档超越了存储库和单个实体.但学习是一个反复的过程. (4认同)
  • 存储库与MVC完全正交.它实际上是由DDD提出的. (2认同)

Gup*_*R4c 15

An IRepository是您希望实现存储库模式时指定的接口.正如@Brian Ball所说,它不是.NET的一部分,它是您创建的界面.

使用存储库模式的开发人员广泛推荐使用接口来实现.例如,在我正在开发的应用程序中,我有5个存储库.4具体和1通用.每一个都继承自一个IRepository确保我不会在实施过程中出现问题的问题.

至于代码示例,我会尝试:

interface IRepository<T> where T : class {
    IQueryable<T> Select();
}
Run Code Online (Sandbox Code Playgroud)

实现为通用存储库:

public class Repository<T> : IRepository<T> where T : class {
    public IQueryable<T> Select() {
        return this.ObjectContext.CreateObjectSet<T>();
    }
}
Run Code Online (Sandbox Code Playgroud)

作为专门的存储库实现:

public class EmployeeRepository : IRepository<Employee> {
    public IQueryable<Employee> Select() {
        return this.ObjectContext.Employees;
    }
}
Run Code Online (Sandbox Code Playgroud)

无论是实现Repository<T>还是EmployeeRepository实现IRepository,它们都会稍微不同地执行查询.通用存储库必须先创建T的对象集,然后才能尝试执行任何操作.

请记住,Repository<T>应该锁定到接口,在那里EmployeeRepository可以实现更专业的方法来完成更复杂的逻辑.

我希望这对你有所帮助.

  • +1好的解释/代码.我唯一要补充的是我个人的偏好是让专业的存储库继承自通用存储库.例如`public class EmployeeRepository:Repository <Employee>`.这样您就不必重新编码泛型方法,例如`IQueryable <Employee> Select()`,因为它将在基本存储库中定义. (5认同)