Exploring ASP - NET Core Fundamentals - Repository Pattern and Usage in EF Core - Referbruv CodeBlog
Exploring ASP - NET Core Fundamentals - Repository Pattern and Usage in EF Core - Referbruv CodeBlog
In the previous article we discussed in detail about the Entity Framework Core
ORM (Object Relational Mapper) developed for .NET Core and how we can inject
the DatabaseContext or the DbContext instance extended by a custom class
which holds the bridge between the .NET Core business layer and the back-end
database by means of DbSets of entity classes which form the code-first approach
of defining and mapping a database object to a class object. We also discussed
that injecting a DbContext object directly into business logic is not a good
practice and we would require a Repository pattern to implement the same. In
this article we will look into what a Repository pattern is and how we can
implement a Repository pattern onto an Entity Framework model and what
advantages it provides over a non-pattern approach.
Let's start from the question of what really a design pattern is. A Design Pattern is
a structural solution designed for a distinct set of problems which can hinder code
structure, behaviour and finally performance. By using a particular design pattern
while programming a solution, we ensure that the code structure and hierarchy
we create is free of a particular problem that design pattern was brought in to
solve. The first step in implementing a design pattern is in identifying the flaw in
the existing code and selecting the respective pattern to implement to overcome
it. Sometimes we use design patterns subconsciously, we don't know that we're
actually implementing a pattern and yet we tend to code in that way. Having a
basic idea of design patterns basically helps code better and thereby improves
maintainability and scalability. In dotnet core, we already implement Singleton
pattern (by defining the lifetimes of services or class objects which we induct into
pipeline and later inject when necessary) and we use Factory patterns as well (for
example the IHttpClientFactory we discussed earlier for handling HttpClient
objects). Although we don't actually implement the behavior, by using the
libraries that dotnet core provides for the respective functionalities, we actually try
to mimic them in our structure. One of the 23 design patterns developed for
various programming problems, the Repository pattern we are about to
implement solves the basic problem of logical abstraction or logical partitioning.
Let's use the same example we've discussed earlier,
public MyController : Controller
{
DatabaseContext context;
this.context = ctx;
context.Users.Add(user);
context.SaveChanges();
}
We start by identifying all the reusable Data Logic, which we shall define using an
interface.
The above interface defines four basic data functionalities which are needed by all
the controllers. Next, we define an implementor that holds an implementation of
the above definition.
public class DataService : IDataService {
DatabaseContext context;
Now that we have an implementation of our DataService, we can simply use this
DataService object in our controller class for handling data logic without the need
for actually having any logic within the controller.
public class MyController : Controller {
IDataService data;
services.AddDbContext<DatabaseContext>(
options => {
//connection string logic
});
services.AddScoped<IDataService, DataService>();
}
...
It can be observed here that the service is defined with a Scoped lifetime, because
as we discussed earlier the DbContext service is of SCOPED lifetime and
CANNOT be injected in a SINGLETON service.
IDataService data;
...
}