Generic Repository or Specific Repository for each entity?

夙愿已清 提交于 2019-11-26 03:27:05

问题


Background

At the company I work for I have been ordered to update an old MVC app and implement a repository pattern for a SQL database. I have created the context of the database using Entity Framework Database-First and got 23 entities.

The first question

Do I need to create a repository for each entity or implement a generic repository for the context? I\'m asking this because I have found following while searching internet:

One repository per domain

You should think of a repository as a collection of domain objects in memory. If you’re building an application called Vega, you shouldn’t have a repository like the following:

public class VegaRepository {}

Instead, you should have a separate repository per domain class, like OrderRepository, ShippingRepository and ProductRepository.

Source: Programming with Mosh: 4 Common Mistakes with the Repository Pattern

The second question

Does a generic repository work for Entity Framework Database-First? This is because I have found following while searching internet:

Entity framework

Do note that the repository pattern is only useful if you have POCOs which are mapped using code first. Otherwise you’ll just break the abstraction with the entities instead (= the repository pattern isn’t very useful then). You can follow this article if you want to get a foundation generated for you.

Source: CodeProject: Repository pattern, done right


回答1:


To begin with, if you are using full ORM like Entity Framework or NHibernate, you should avoid implementing additional layer of Repository and Unit Of Work. This is because; the ORM itself exposes both Generic Repository and Unit Of Work.
In case of EF, your DbContext is Unit Of Work and DbSet is Generic Repository. In case of NHibernate, it is ISession itself.
Building new wrapper of Generic Repository over same existing one is repeat work. Why reinvent the wheel?

But, some argue that using ORM directly in calling code has following issues:

  1. It makes code little more complicated due to lack of separation of concerns.
  2. Data access code is merged in business logic. As a result, redundant complex query logic spread at multiple places; hard to manage.
  3. As many ORM objects are used in-line in calling code, it is very hard to unit test the code.
  4. As ORM only exposes Generic Repository, it causes many issues mentioned below.

Apart from all above, one other issue generally discussed is "What if we decide to change ORM in future". This should not be key point while taking decision because:

  • You rarely change ORM, mostly NEVER – YAGNI.
  • If you change ORM, you have to do huge changes anyway. You may minimize efforts by encapsulating complete data access code (NOT just ORM) inside something. We will discuss that something below.

Considering four issues mentioned above, it may be necessary to create Repositories even though you are using full ORM - This is per case decision though.

Even in that case, Generic Repository must be avoided. It is considered an anti-pattern.

Why generic repository is anti-pattern?

  1. A repository is a part of the domain being modeled, and that domain is not generic.
    • Not every entity can be deleted.
    • Not every entity can be added
    • Not every entity has a repository.
    • Queries vary wildly; the repository API becomes as unique as the entity itself.
    • For GetById(), identifier types may be different.
    • Updating specific fields (DML) not possible.
  2. Generic query mechanism is the responsibility of an ORM.
    • Most of the ORMs expose an implementation that closely resemble with Generic Repository.
    • Repositories should be implementing the SPECIFIC queries for entities by using the generic query mechanism exposed by ORM.
  3. Working with composite keys is not possible.
  4. It leaks DAL logic in Services anyway.
    • Predicate criteria if you accept as parameter needs to be provided from Service layer. If this is ORM specific class, it leaks ORM into Services.

I suggest you read these (1, 2, 3, 4, 5) articles explaining why generic repository is an anti-pattern. This other answer discusses about Repository Pattern in general.

So, I will suggest:

  • Do NOT use repository at all, directly use ORM in your calling code.
  • If you have to use repository, then do not try to implement everything with Generic Repository.
    Instead, optionally create very simple and small Generic Repository as abstract base class. OR you can use Generic Repository exposed by your ORM as base repository if ORM allows it.
    Implement Concrete Repositories as per your need and derive all them from Generic Repository. Expose concrete repositories to calling code.
    This way you get all the good of generic repository still bypassing its drawbacks.
    Even though very rare, this also helps switching ORM in future as ORM code is cleanly abstracted in DAL/Repositories. Please understand that switching ORM is not a primary objective of Data Access Layer or Repository.

In any case, do not expose Generic Repository to calling code.

Also, do not return IQueryable from concrete repositories. This violates basic purpose of existence of Repositories - To abstract data access. With exposing IQueryable outside the repository, many data access decisions leak into calling code and Repository lose the control over it.

do I need to create a repository for each entity or implement a generic repository for the context

As suggested above, creating repository for each entity is better approach. Note that, Repository should ideally return Domain Model instead of Entity. But this is different topic for discussion.

does a generic repository works for EF Database First?

As suggested above, EF itself exposes Generic Repository. Building one more layer on it is useless. Your image is saying the same thing.



来源:https://stackoverflow.com/questions/51771407/generic-repository-or-specific-repository-for-each-entity

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!