Search code examples
.netasp.net-mvcentity-frameworkrepository-patternsolid-principles

SOLID principles, Repository pattern and EntityFramework cache in Asp Net Mvc


I have a visual studio solution using solid pattern. I have a IRepository (Crud implementation), IDbFactory (used by a repository), IUnitOfWork. I also have services, who uses repositories to build custom querys and complex database operation. I am using also IoC pattern with Ninject. In a web mvc controller I use only services to access to database. A repository receive a IDbFactory who build a EntityFramework Context. I have some problems:

  • In a service when i have to access to two tables for join them i should use two repositories, calling the GetAll() method of both of them. In this case both repositories should share the same EntityFramework Context.
  • The previous case indicates me that the DbContext should be shared by All repositories, so I can join IQueryables in a service from different repositories.
  • To a accomplish this goal I configured in the IoC container, the DbContext in singleton scope. So every repository shares the same DbContext.
  • The problem with this solution is that the DbContext have a cache. So, when a external process (different to the web project) changes my data the DbContext do not realize it, and the Web project do not shows real data sometimes.
  • I read about destroy the DbContext in every repository call, but i cant do this because every repository should use the same DbContext

I there something wrong with my Project structure? This is something i must fix in the repository layer? What shoul I do? The project is in developing stage, so I can change the data access architecture. I like use IQueryables in the controller so users filters in data grids produce sql querys.


Solution

  • Well, in terms of your stated issue here, there's nothing wrong with your project structure. The problem derives from using a Singleton scope. You should be using Request scope, instead, for a web application. This ensures that you get a new context with each request, so there will not be overlap between different requests and even different clients, which can be extremely dangerous.

    That said, your project structure is over-engineered. The repository/unit of work patterns are intended for low-level data access. An ORM, like Entity Framework, handles all that, and in fact, Entity Framework already implements these patterns. The DbContext is the unit of work and each DbSet is a repository. Adding your own repository/unit of work layer on top of this is redundant and unnecessary. Your services should utilize your Entity Framework context directly. Even then, having a plurality of services is probably unnecessary as well, depending on what they do. If they all work with the same data source (i.e. an Entity Framework context) and particularly if they all work with the same Entity Framework context, then they should really all be rolled into one.

    In my own personal projects, I utilize a single "service" class with generic methods per unique context instance. The generic methods let me work with any entity belonging to that context without having to new up additional instances of the "service" class. By ensuring that everything implements one or more interfaces and using dependency injection to satisfy interface constraints, the underlying data layer is completely factored out. I have a series of posts that goes into greater detail if you're interested.

    I say all this because it seems you're overly focused on patterns and "best practices". Those are just guides. They're like training wheels on a bicycle. They're all based on various principles of good code design. Learn and apply the principles and don't worry about checking all the boxes on some sort of list of design patterns.

    As an interesting aside, Stack Overflow's core codebase actually eschews a number of patterns (even dependency injection) because they're laser-focused on raw performance, and some design patterns, when applied, actually hinder performance. The point is that how an application is designed should be based on the needs of the particular application. Design patterns should only be applied in as much as they are congruent with the needs of your application, not just because you think you're supposed to.