C# 实体框架与存储库模式

C# 实体框架与存储库模式,c#,entity-framework,C#,Entity Framework,我想知道存储库模式在使用实体框架的项目中的有用性。关于这一点有相反的说法——有人说EF是存储库和工作单元模式本身的实现,所以不需要将其封装在下一个抽象层中,有人认为它具有分离DAL和BL以及更容易创建单元测试等优点。根据我的经验,我经常遇到以下方法(通常,不仅在EF项目中): 据我所知,服务不应该有任何DAL操作——这意味着我们不应该从存储库返回IQueryable集合,因为这样查询将在存储库之外执行,单元测试将不完全可靠(LINQ到实体和LINQ到对象之间的差异) 我在这里看到了查询效率的问题

我想知道存储库模式在使用实体框架的项目中的有用性。关于这一点有相反的说法——有人说EF是存储库和工作单元模式本身的实现,所以不需要将其封装在下一个抽象层中,有人认为它具有分离DAL和BL以及更容易创建单元测试等优点。根据我的经验,我经常遇到以下方法(通常,不仅在EF项目中):

据我所知,服务不应该有任何DAL操作——这意味着我们不应该从存储库返回IQueryable集合,因为这样查询将在存储库之外执行,单元测试将不完全可靠(LINQ到实体和LINQ到对象之间的差异)

我在这里看到了查询效率的问题——我们通常会从数据库中获取比需要更多的数据,然后在内存中进行过滤

例如,让我们考虑<强> BooValuyPosiple(String登录,String密码)方法。 在这种情况下,我们需要从数据库中获取整个用户实体,例如,它可以有50个属性,仅用于密码验证。当然,我们可以在存储库中创建许多方法,如:

string GetPasswordHash(string login) 

不需要从数据库获取整个实体,但在我看来,这可能是一个“小”开销

我们还可以将VerifyPassword功能从服务移动到存储库,然后我们应该问自己是否需要两层——存储库和服务。但如果我们合并它们,我们将失去分离DAL和BL层的好处——单元测试实际上就是集成测试。所以,也许将其全部保存在控制器中并注入模拟的DbContext或使用类似于单元测试的努力会更简单(更好)

我将非常感谢您的回答,您如何看待这一点,以及您如何在项目中解决这一问题

更新

我知道存储库模式允许轻松地将数据源/提供者更改为其他类型,如nHibernate、LINQ转换为SQL、普通ADO等


但您能告诉我如何在存储库API中实现排序和分页吗?我的意思是,将排序和分页规范传递给存储库的最佳方式是什么?我看到一些传递LINQ的函数谓词,但这将使存储库与LINQ紧密耦合—将其与普通ADO、存储过程等一起使用会有问题。在我看来,创建许多方法,如GetUsersOrderedByNameDesc()等是疯狂的。所以,也许可以为规范创建自己的类,伪造并传递排序/分页标准,并在存储库中处理它?如果是,你能给我一些实施的例子吗?

我将尝试回答你的核心问题。这是我的两分钱。 为什么是存储库与实体框架。在设计或选择哪一个时,您需要回答我建议您提出的一些问题:

  • 您的项目是否有可能与不同的存储库进行对话?如果是,那么实体框架上的存储库模式是有意义的
  • 拥有存储库模式还将允许您更轻松地设置测试框架,您可以在其中拥有存储库模式(DAL)将使用的模型数据库
  • <> LI>您可能还想考虑对数据模型的更改可以渗透到业务逻辑与实体框架的更改。
    我不确定实际的问题是什么,所以这是一个评论,而不是让你更具体的答案。当然,拥有存储库层和独立的服务层是个好主意。上面提到的VerifyPassword是一种很好的服务方法,它只需要用存储库语言而不是DAL语言来实现。我不同意这一点,但这没关系。它只是表明这个问题对于StackOverflow的问答格式来说太宽泛了。
    public interface IUsersRepository
    {
      IEnumerable<User> GetAll();
      User Get(int id);
      User GetByLogin(string login);
      void Update(User item);
      void Delete(int id);
      void Delete(User item);
      // ...
    }
    
    public interface IUsersService
    {
      // ...
      bool VerifyPassword(string login, string password);
      void ChangePassword(string login, string password);
      // ...
    }
    
    string GetPasswordHash(string login) 
    
    bool VerifyPassword(string login, string passwordHash) 
    {
      return db.Users.Any(x => x.Login = login && x.Password = passwordHash);
    }