EFCore Repository Implementation in ASP.NET Core

Entity Framework Repository Implementation in ASPNET Core

In this article, we will learn Entity Framework Repository Implementation for Relational databases like SQL in the .NET Core or ASP.NET Core 3.1 or .NET 6 application.

We already discussed basic details on getting started with EFCore in ASP.NET Core in our last article.

In Today’s article, we shall see how to extend the same existing implementation to use a better pattern i.e Repository.

Below are the steps which we shall be following to create a Repository,

EFCore scaffolding as Repository and UoW

EFCore is an ORM-Object-relational mapping framework that helps to represent the Database into the object-oriented programming model in the .NET Core ecosystem helping to interact and perform CRUD operation on relational DB without hassle.

Repository design patterns fit into any NoSQL or Relational DB requirements and also can be used for multiple other requirements.

Entity Framework DBContext as Repository and UOW

Using tools like Entity Framework gives us DBContext which already represents repository and UoW (Unit Of Work) implementation with very minimal effort.

The best thing is you can use DBContext anywhere from your code.

This DBContext can be DI (Dependency Injected ) from the API pipeline or Middleware as needed or can be consumed directly.

However, if you see DBContext is a class and not an Interface.

If you need to perform Test-Driven Development like Unit Testing, you will find a few challenges in mocking DBContext to simulate the Data access.

So considering testability as an important principle, one can easily implement a Repository.

Repository encourages a more loosely coupled approach to accessing our data from the database.

The code becomes cleaner and maintainable and highly extensible.

Entity Framework Repository Implementation in ASPNET Core

Entity Framework- Create Models using Schema

Do you follow schema modeling ??.

EFCore works very well for the Database First approach.

Where it lets you create the required scaffolding and domain entities using the existing Database.

However, You can follow the code-first approach as well followed by using Migration and Update database commands to create the database.

Entity Framework – using Database First

We shall be learning EFCore using Database first approach where we already have an existing Database called ‘Master‘ and a table name called Employee.

SQL Database Schema

We can start with the below simple Database schema,

EFCore Database First Entity Framework Database First

I have discussed how to do ECore scaffolding and generate domain entities in the below article.

Once you are ready with scaffolding please use the repository to access DBContext objects as below.

Entity Framework- Define Repository Interfaces

Repository Interfaces will be defined as below,

public interface IEmployeeRepository
{
    IEnumerable<Employee> GetEmployees();
    Employee GetEmployeeByID(int employeeID);
    void InsertEmployee(Employee employee);
    void DeleteEmployee(int employeeID);
    void UpdateEmployee(Employee employee);
}

We shall define repository class specific to the context, i.e. here EmployeeRepository will be dealing with Employee DBContext.

Entity Framework- Define Repository Class

Please see the implementation for the Repository class performing CRUD operation below.

EmployeeContext object is accessed using EmployeeRepository Constructor injections as below,

public class EmployeeRepository : IEmployeeRepository
    {
        private readonly EmployeeContext _context;
        public EmployeeRepository(EmployeeContext context)
        {
            _context = context;
        }
        public IEnumerable<Employee> GetEmployees()
        {
            return _context.Employee.ToList();
        }
        public Employee GetEmployeeByID(int employeeID)
        {
            return _context.Employee.Find(employeeID.ToString());
        }
        public void InsertEmployee(Employee employee)
        {
            _context.Employee.Add(employee);
        }
        public void DeleteEmployee(int employeeID)
        {
            Employee employee = _context.Employee.Find(employeeID);
            _context.Employee.Remove(employee);
        }
        public void UpdateEmployee(Employee employee)
        {
            _context.Entry(employee).State = EntityState.Modified;
        }
    }

EmployeeContext is created using database Scaffolding DBContext Commands as discussed in our Getting Started using EFCore article.

Now that our Repository is ready, this can be integrated into the code.

If following non-DDD or DDD architecture this repository will be responsible for performing CRUD and will also be used for data persistence through DBContext.

Using a Repository in API/Service

Here is an example of how I am using the repository in EmployeeController (In a similar way this repository can be interfaced from the Domain or Business layer as required (if you have any).

EmployeeRepository object is accessed using EmployeeController’s Constructor injections.

Below is a very simple and minimal implementation,

    [Route("api/[controller]")]
    [ApiController]
    public class EmployeeController : ControllerBase
    {
        private readonly IEmployeeRepository _employeeRepository;
        public EmployeeController(IEmployeeRepository employeeRepository)
        {
            _employeeRepository = employeeRepository;
        }
        // GET: api/Employee
        [HttpGet]
        public ActionResult<IEnumerable<Employee>> Get()
        {
            return Ok(_employeeRepository.GetEmployees());
        }
        // GET: api/Employee/5
        [HttpGet("{id}")]
        public ActionResult Get(int id)
        {
            return Ok(_employeeRepository.GetEmployeeByID(id));
        }
        // POST: api/Employee
        [HttpPost]
        public void Post([FromBody] Employee value)
        {
            _employeeRepository.InsertEmployee(value);
        }
        // DELETE: api/5
        [HttpDelete("{id}")]
        public void Delete(int employeeID)
        {
            _employeeRepository.DeleteEmployee(employeeID);
        }
    }

Repository and DBContext using IoC Dependency injection Container

Please initialize Repository and DBContext in the Service Container as below,

Dependency injection Container in .NET 3.1

public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddScoped<IEmployeeRepository, EmployeeRepository>();
            services.AddDbContext<EmployeeContext>(options =>
            {
                options.UseSqlServer(Configuration.GetConnectionString("EmployeeDB"),
                 sqlServerOptionsAction: sqlOptions =>
                 {
                     sqlOptions.EnableRetryOnFailure();
                 });
            });
        }

Dependency injection Container in .NET 6 and above

If using .NET 6 and above, please use builder instances to add the lifetime of required services,

Example

        
            builder.services.AddScoped<IEmployeeRepository, EmployeeRepository>();
            builder.services.AddDbContext<EmployeeContext>(options =>
            {
                options.UseSqlServer(Configuration.GetConnectionString("EmployeeDB"),
                 sqlServerOptionsAction: sqlOptions =>
                 {
                     sqlOptions.EnableRetryOnFailure();
                 });
            });

Please note that the repository instance lifetime in your IoC container should be set as Scoped (same as DBContext) as a good practice.

As shown in the above code, we also have resiliency implemented for SQL Connection using EnableRetryOnFailure() added with the DBContext instance.

As a good practice, implement resiliency in SQL operation to address any issues related to Transient errors.

One can also implement a more Generic repository around DBContext if needed addressing multiple Domain models as discussed below article if needed.

You are all set to use a repository in your code.

Other References :

Do you have any comments or ideas or any better suggestions to share?

Please sound off your comments below.

Happy Coding !!

Summary

Today in this article we learned how to implement a Repository around SQL database using the EFCore ORM framework.

Application with a complex business/domain model gets a huge advantage over the Repository.

It provides an abstraction that not only isolates the business objects from the database access code but also provides a clean separation of concerns in an Object-oriented way.



Please bookmark this page and share it with your friends. Please Subscribe to the blog to receive notifications on freshly published(2024) best practices and guidelines for software design and development.