简体   繁体   English

实体框架与存储库模式

[英]Entity Framework vs repository pattern

I'm wondering about usefulness of repository pattern in project using Entity Framework. 我想知道存储库模式在使用Entity Framework的项目中是否有用。 There are opposite claims about this - some say that EF is implementation of repository and Unit of Work pattern itself, so there is no need to wrap it in next abstraction layer, some argue that it has advantages like separation of DAL and BL and easier creation of unit tests. 对此有相反的主张-有人说EF是存储库和工作单元模式本身的实现,因此无需将其包装在下一个抽象层中,有人认为EF具有诸如DAL和BL分离以及易于创建的优点。单元测试。 In my experience, I often come across the following approach (generally, not only in EF projects): 以我的经验,我经常遇到以下方法(通常,不仅在EF项目中):

Repository (DAL) <-> Service (BL) <-> Controller

Repository + Service + Type = Model

Repository has methods responsible for data access only ie: 存储库具有仅负责数据访问的方法,即:

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);
  // ...
}

Often, there is used generic repository instead, which methods receive functions for filtering, sorting etc. 通常,使用通用存储库代替,这些方法接收用于过滤,排序等功能。

Service in turn uses repository and contains business logic ie: 服务又使用存储库并包含业务逻辑,即:

public interface IUsersService
{
  // ...
  bool VerifyPassword(string login, string password);
  void ChangePassword(string login, string password);
  // ...
}

As I understand, service shouldn't have any DAL operations - this means that we shouldn't ie return IQueryable collections from repository, because then query will be executed outside repository and unit tests will not be fully reliable (differences between LINQ-to-Entities and LINQ-to-Objects). 据我了解,服务不应该进行任何DAL操作-这意味着我们不应该从存储库返回IQueryable集合,因为那样一来,查询将在存储库外部执行,并且单元测试将不完全可靠(LINQ-to-实体和LINQ到对象)。

I see a problem with queries efficiency here - we will often get more data from database than needed and then filter it in memory. 我在这里看到查询效率的问题-我们通常会从数据库中获取比所需更多的数据,然后将其过滤到内存中。

For example, let's consider bool VerifyPassword(string login, string password) method. 例如,让我们考虑bool VerifyPassword(字符串登录名,字符串密码)方法。

In this case we need to get whole User entity from database, which can have 50 properties for example, for password verification purpose only. 在这种情况下,我们需要从数据库中获取整个User实体,该实体可以具有50个属性,例如,仅用于密码验证。 We can, of course, create many methods in repository like : 当然,我们可以在存储库中创建许多方法,例如:

string GetPasswordHash(string login) 

or 要么

bool VerifyPassword(string login, string passwordHash) 
{
  return db.Users.Any(x => x.Login = login && x.Password = passwordHash);
} 

without need to get whole entity from database, but in my opinion this can be a "little" overhead. 无需从数据库中获取整个实体,但是我认为这可能是“少量”的开销。

We can also move VerifyPassword function from service to repository - then we should ask ourself a question whether two layers - repository and service are needed. 我们还可以将VerifyPassword函数从服务移动到存储库-然后我们应该问自己一个问题,是否需要两层-存储库和服务。 But if we merge them, we will lose benefits of separating DAL and BL layers - unit tests would be integration tests in reality. 但是,如果将它们合并,我们将失去分离DAL和BL层的好处-单元测试实际上就是集成测试。 So maybe it would be simplier (and better) to keep it all in controller and inject mocked DbContext or use something like Effort for unit tests? 因此,将其全部保留在控制器中并注入模拟的DbContext或对单元测试使用类似Effort的方法也许更简单(更好)。

I will be grateful for your answers how you see this and how you solve this problem in your projects. 对于您如何看待这一问题以及如何在项目中解决此问题,我将不胜感激。

UPDATE UPDATE

I understand that repository pattern allows to easily change data source/provider to other like nHibernate, LINQ-to-SQL, plain ADO and so on. 我知道,存储库模式可以轻松地将数据源/提供程序更改为nHibernate,LINQ-to-SQL,纯ADO等。

But could you tell me how do you implement sorting and paging in your repository API? 但是您能告诉我如何在存储库API中实现排序和分页吗? I mean what's the best way to pass sorting and paging specification to repository? 我的意思是将排序和分页规范传递到存储库的最佳方法是什么? I see that some passes function predicates for LINQ but this will tightly couple repository with LINQ - using it with plain ADO, stored procedures etc. would be problematic. 我看到一些用于LINQ的传递函数谓词,但这将使存储库与LINQ紧密耦合-将其与普通ADO,存储过程等一起使用会出现问题。 Creating many methods like GetUsersOrderedByNameDesc() etc. is crazy in my opinion. 在我看来,创建诸如GetUsersOrderedByNameDesc()等的许多方法非常疯狂。 So maybe create your own class for specification, forge and pass sorting/paging criterias, and process it in repository? 因此,也许可以为规范创建自己的类,伪造并通过排序/分页标准,然后在存储库中对其进行处理? If yes, can you provide me some example of implementation? 如果是,您能否提供一些实施示例?

I will try to attempt your core question. 我将尝试尝试您的核心问题。 Here are my two cents. 这是我的两分钱。 Why repository vs entity framework. 为什么选择存储库还是实体框架。 You will need to answer some of the questions I propose you ask when designing or picking which one: 在设计或选择哪个问题时,您需要回答我建议您提出的一些问题:

  1. Is there a chance your project will have different repositories it will talk to? 您的项目是否有可能与之交谈的不同存储库? If yes, then repository pattern over entity framework makes sense. 如果是,则实体框架上的存储库模式很有意义。
  2. Having a repository pattern will also allow you to set up your test framework more easily where you can have your mockup db that the repository pattern (DAL) will use. 拥有存储库模式还可以使您更轻松地设置测试框架,在该库中可以使用存储库模式(DAL)使用的模型数据库。
  3. You may also want to consider the changes to your data model can percolate back to changes in your business logic with the entity framework. 您可能还需要考虑对数据模型的更改可以渗透到实体框架的业务逻辑更改中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM