问题
Let's start with two quotes that sums this issue up: "Wrapping up DbContext is a leaky abstraction. No matter what, you'll end up in some kind of dependency on EF in your services/controller layer." quote ref And the second quote:
"DbContext Class
Represents a combination of the Unit-Of-Work and Repository patterns and enables you to query a database and group together changes that will then be written back to the store as a unit." MSDN
Please do not say that the repository pattern allows you to simply swap out your database, it does not. Has anyone even ever done that with a mature application? Please also do not answer that the Repository pattern should not expose IQueryable, I think that is just another way saying you don't trust the people you work with.
I am all for encapsulation, code coverage/testability but since this popular repo pattern for EF exposes IQueryable there is no longer a need for the pattern it seems:
public interface IRepository<T> where T : class
{
IQueryable<T> GetAll();
T GetById(int id);
IEnumerable<T> Get(Expression<Func<T, bool>> filter = null,Func<IQueryable<T>,IOrderedQueryable<T>> orderBy = null, string includeProperties = "");
void Add(T entity);
void Update(T entity);
void Delete(T entity);
void Delete(int id);
}
The only benefits of the repository pattern combined with the UOW pattern are: 1. Easily enable the Dependency Injection pattern for increase testability/code coverage 2. Encapsulate the complexity that exists with external integration (web service calls to different vendors, web apis, databases, etc..)
So what encapsulation am I getting that I do not get by using MyDbContext : DbContext class? My ORM is the abstraction Sure I get some uniformity of the controllers with the UOW of work and the common queries like Add and Delete, but is that really worth the effort. Can't I just trust my developers to be uniform and when they do it a little their way, just don't get OCD about it. AND since a controller can write any query it wants does this not fly in the face of unit testing? AND (even larger caps lol) if I have a third party API to call, I can make this accessible in MyDbContext class for the controllers so it seems like just another data call to the controller.
I say again, why not use the ORM directly, it is the data abstraction!
Here is some arguments against the repository pattern:
http://ayende.com/blog/4784/architecting-in-the-pit-of-doom-the-evils-of-the-repository-abstraction-layer
http://ayende.com/blog/3955/repository-is-the-new-singleton
http://lostechies.com/jimmybogard/2012/09/20/limiting-your-abstractions/
http://lostechies.com/jimmybogard/2012/10/08/favor-query-objects-over-repositories/
Here is a proper argument for the repository pattern (not convincing enough though): http://www.sapiensworks.com/blog/post/2012/10/10/Do-We-Need-The-Repository-Pattern.aspx
回答1:
I think I'll go bonkers if I see that Ayende post one more time. Let's take each thing slowly:
Generic Repository has limited applicability. Personally, I'm using it ONLY for domain repositories and ONLY when I'm storing the aggregate roots in a serialized form. For the rest of things (read: view models, reports) I'd have a repository designed for the needs of the layer asking for those models.
IQueryable is pretty much a query builder. You don't tell the repository how to build something (IQUeryable) you just ask something from it. If you're using IQueryable you're already doing part of the repository's job (breaking the higher layer's SRP). Also exposing IQueryable means the higher layer MUST know about pocos/entities used to create the query. IF your boss decides that from now on you'll get the data from a web service, what would you do with all those IQueryable and ORM entities sprinkled everywhere? Or the RDBMS is too slow so let's use a Document Db? Yes, it might suport linq but are you sure you'll have the same entities defined?
Don't trust your developers. Trust a proper architecture, one where you don't mix layer responsibilities and where SRP (Single Responsibility Principle) is respected. If you're designing, let's say View Models according to how data is stored in db and not according what you need in a view, you have a tight coupling problem.
The reason of not using a repo because you don't need to change the ORM or the storage tech is IMHO a reason similar to: why use a DI Container or interfaces, there is a slim chance those classes would change and we can do manual injection anyway.
Using a repository means you don't have to care about how and where from your models are retrieved. The repository exposes business friendly semantics (GetTopSellingProducts). With an orm you have to build the query (everybody loves doing joins and subqueries in linq), know about the entities, do the projections etc. Why should the higher layer care about these details? It's the 'ask, don't tell how' principle (j/k)
It's all about maintainable code after all, I want my code to be easily understood.
回答2:
I say again, why not use the ORM directly, it is the data abstraction!
It is a data abstraction not the data abstraction.
It's about abstracting your ORM should you need to switch it out. Not about what goodies a generic repo could offer over the DbContext directly. If you did need to switch out EF and DbContext and it was highly coupled you would need to edit all sections of your code that use DbContext or be forced to implement a DbContext interface on whatever ORM you switch to.
In saying that I think the likelyhood of switching ORM in most applications is slim and the convenience of using DbContext directly outweighs the risk of a coupling to EF. However, I still see why some would want to do it depending on the application requirements and lifespan.
来源:https://stackoverflow.com/questions/14531688/what-are-the-advantages-to-the-generic-repository-pattern-uow-pattern-with-an