EFCore Implementation Using .NET core

Introduction

 
In this post we will learn about Entity Framework core implementation in .Net Core API. The .Net Core API application has been explained in the below post.
Before we start please go through the above article to understand Entity Framework core. We are building an applicaiton on top of this.
 

About Repository Pattern

 
Repository Pattern is abstract layer to persistence layer and reduces the complexity of the code. An application should not depend on persistence implementation directly. It helps to change the Db layer implementation without direct impact to the application, and we can easily add mock repository which will help the unit testing.
 
Step 1
 
Create a “Repositories” folder and create “IEmployeeRepository.cs” and “EmployeeRepository.cs” class files.
 
EFCore Implementation Using .NET core
 
Add the below methods in “IEmployeeRepository.cs” and “EmployeeRepository.cs” class files.
  1. public interface IEmployeeRepository  
  2.     {  
  3.         IEnumerable<Employee> GetAllEmployee();  
  4.         Employee GetEmployee(int employeeId, bool isWithAddress);  
  5.         IEnumerable<Address> GetAddress(int employeeId);  
  6.         Address GetEmployeeAddress(int employeeId, int addressId);  
  7.     }  
Step 2
 
Implement “IEmployeeRepository” interface in “EmployeeRepository” class.
  1. public class EmployeeRepository : IEmployeeRepository  
  2.   {  
  3.       public IEnumerable<Address> GetAddress(int employeeId)  
  4.       {  
  5.           throw new NotImplementedException();  
  6.       }  
  7.   
  8.       public IEnumerable<Employee> GetAllEmployee()  
  9.       {  
  10.           throw new NotImplementedException();  
  11.       }  
  12.   
  13.       public Employee GetEmployee(int employeeId)  
  14.       {  
  15.           throw new NotImplementedException();  
  16.       }  
  17.   
  18.       public Address GetEmployeeAddress(int employeeId, int addressId)  
  19.       {  
  20.           throw new NotImplementedException();  
  21.       }  
  22.   }  
Inject the "Dbcontext" class in “EmployeeRepository” class.
  1. private readonly EmployeeDbContext _context;  
  2.      public EmployeeRepository(EmployeeDbContext context)  
  3.      {  
  4.          _context = context;  
  5.      }  
Step 3
 
We will implement “IEmployeeRepository” interface methods that will pull data from "EmployeeDbContext".
  1. public class EmployeeRepository : IEmployeeRepository  
  2.    {  
  3.        private readonly EmployeeDbContext _context;  
  4.        public EmployeeRepository(EmployeeDbContext context)  
  5.        {  
  6.            _context = context;  
  7.        }          
  8.   
  9.        public IEnumerable<Employee> GetAllEmployee()  
  10.        {  
  11.            return _context.Employees.OrderBy(e => e.EmployeeName).ToList();  
  12.        }  
  13.   
  14.        public Employee GetEmployee(int employeeId, bool isWithAddress)  
  15.        {  
  16.            if (isWithAddress)  
  17.            {  
  18.                return _context.Employees.Include(e => e.EmployeeAddress)  
  19.                            .Where(a => a.Id == employeeId).FirstOrDefault();  
  20.            }    
  21.            return _context.Employees.Where(e => e.Id==employeeId).FirstOrDefault();  
  22.        }  
  23.   
  24.        public Address GetEmployeeAddress(int employeeId, int addressId)  
  25.        {  
  26.            return _context.Addresses.Where(a => a.Id == employeeId  
  27.                                        && a.EmployeeId == employeeId).FirstOrDefault();  
  28.        }  
  29.   
  30.        public IEnumerable<Address> GetAddress(int employeeId)  
  31.        {  
  32.            return _context.Addresses.Where(a => a.Id == employeeId).ToList();  
  33.        }  
  34.    }  
Also register the "EmployeeRepository" in "Startup.cs" -> ConfigureServices method. 
  1. services.AddScoped<IEmployeeRepository, EmployeeRepository>();  
Step 4
 
We will inject the "EmployeeRepository" in "EmployeeController". 
  1. private readonly ILogger<EmployeeController> _logger;  
  2.       private readonly IEmployeeRepository _employeeRepository;  
  3.       public EmployeeController(ILogger<EmployeeController> logger, IEmployeeRepository employeeRepository)  
  4.       {  
  5.           _logger = logger;  
  6.           _employeeRepository = employeeRepository;  
  7.       }  
 We can call the "GetAllEmployee" repository method and map repository data to "EmployeeModel" manually.
  1. public IActionResult GetAllEmployees()  
  2.        {  
  3.            var employeeData = _employeeRepository.GetAllEmployee();    
  4.            var result = new List<EmployeeModel>();    
  5.            foreach (var employee in employeeData)  
  6.            {  
  7.                result.Add(new EmployeeModel  
  8.                {  
  9.                    EmployeeId=employee.Id,  
  10.                    EmployeeName=employee.EmployeeName,  
  11.                    Skill=employee.Skill,  
  12.                    Email=employee.Email  
  13.                });  
  14.            }    
  15.            if (result == null)  
  16.            {  
  17.                return NotFound();  
  18.            }    
  19.            return Ok(result);  
  20.        }  
Step 5
 
We will run the application and check whether we will able to get the records from the DB or not.
 
EFCore Implementation Using .NET core
 
We got the 3data for the 3 employees from the DB as expected. 
 
Step 6
 
We will implement the "GetEmployee" method with "employeeId" input. We can notice that "employeeAddress" field was empty array.
 
EFCore Implementation Using .NET core 
 
If we pass "IsWithAddress" parameter as true, we will get employee details with Address.
 
EFCore Implementation Using .NET core
 
Step 7
 
Similary we will implement AddressController by adding the "EmployeeRepository" and invoking the Address methods. 
  1.     [ApiController]  
  2.     [Route("api/employee/{employeeId}/address")]  
  3.     public class AddressController : ControllerBase  
  4.     {  
  5.   
  6.         private readonly ILogger<EmployeeController> _logger;  
  7.         private readonly IEmployeeRepository _employeeRepository;  
  8.         public AddressController(ILogger<EmployeeController> logger, IEmployeeRepository employeeRepository)  
  9.         {  
  10.             _logger = logger;  
  11.             _employeeRepository = employeeRepository;  
  12.         }  
  13.   
  14.         // GET: api/<controller>  
  15.         [HttpGet]  
  16.         public IActionResult GetAllAddress(int employeeId)  
  17.         {    
  18.             if (!_employeeRepository.IsEmployeeAvailable(employeeId))  
  19.             {  
  20.                 return NotFound();  
  21.             }  
  22.             var addressData = _employeeRepository.GetAddress(employeeId);    
  23.             var result = new List<AddressModel>();  
  24.   
  25.             foreach (var address in addressData)  
  26.             {  
  27.                 result.Add(new AddressModel  
  28.                 {  
  29.                     Id = address.Id,  
  30.                     AddressDetail = address.AddressDetail  
  31.                 });  
  32.             }    
  33.             if (result == null)  
  34.             {  
  35.                 return NotFound();  
  36.             }    
  37.             return Ok(result);  
  38.         }    
  39.   
  40.         [HttpGet("{id}", Name = "GetEmployeeAddress")]  
  41.         public IActionResult GetEmployeeAddress(int employeeId, int id)  
  42.         {  
  43.             if (!_employeeRepository.IsEmployeeAvailable(employeeId))  
  44.             {  
  45.                 return NotFound();  
  46.             }    
  47.             var address = _employeeRepository.GetEmployeeAddress(employeeId, id);  
  48.   
  49.             if (address == null)  
  50.             {  
  51.                 return NotFound();  
  52.             }       
  53.             var employeeAddress = new AddressModel()  
  54.             {  
  55.                 Id = address.Id,  
  56.                 AddressDetail = address.AddressDetail  
  57.             };    
  58.             return Ok(employeeAddress);  
  59.         }  
  60.     }  
Once we run the below endpoint, we are able to access the address data.
 
EFCore Implementation Using .NET core
 
We can also get the employee address.
 
EFCore Implementation Using .NET core
 
Step 8
 
We manually mapped our entities and models,  instead we will add "Automapper" package. "Automapper" is a convention mapped object mapper which helps to map DB entities and model (DTO) class properties.
 
Install "AutoMapper" and "AutoMapper.Extensions.Microsoft.DependencyInjection" packages from NuGet.
 
Register "AutoMapper" services in "Services.cs" -> Configureservice method. 
  1. services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());  
Create Mapper files
 
Create a "Mappers" folder and "EmployeeMapper" class file, which will  inherit from Profile base class (Automapper library). 
  1. public class EmployeeMapper: Profile  
  2.     {  
  3.         public EmployeeMapper()  
  4.         {  
  5.             CreateMap<Employee, EmployeeModel>();  
  6.         }  
  7.     }  
Inject the "AutoMapper" -> "IMapper" in "EmployeeController" constructor. 
  1. private IMapper _mapper;  
  2.   
  3.         public EmployeeController(ILogger<EmployeeController> logger, IEmployeeRepository employeeRepository, IMapper mapper)  
  4.         {  
  5.             _logger = logger;  
  6.             _employeeRepository = employeeRepository;  
  7.             _mapper = mapper;  
  8.         }  
Change all the manual mapping code to Automapper mapping using "Map" method. 
  1. _mapper.Map<IEnumerable<EmployeeModel>>(employeeData)  
After using Automapper, make sure all the code is working fine.
 
Step 9
 
Added the below code for your reference.
 
Progaram.cs
  1. public static void Main(string[] args)  
  2.        {  
  3.            var host = CreateHostBuilder(args).Build();    
  4.            using (var scope = host.Services.CreateScope())  
  5.            {  
  6.                try  
  7.                {  
  8.                    var context = scope.ServiceProvider.GetService<EmployeeDbContext>();  
  9.                    context.Database.EnsureDeleted();  
  10.                    context.Database.Migrate();  
  11.                }  
  12.                catch (Exception)  
  13.                {  
  14.                    throw;  
  15.                }  
  16.            }  
  17.            host.Run();  
  18.        }  
Startup.cs
  1. public class Startup  
  2. {       
  3.     private readonly IConfiguration _configuartion;  
  4.   
  5.     public Startup(IConfiguration configuartion)  
  6.     {  
  7.         _configuartion = configuartion;  
  8.     }    
  9.     public void ConfigureServices(IServiceCollection services)  
  10.     {  
  11.         services.AddMvc();    
  12.         services.AddScoped<IEmployeeRepository, EmployeeRepository>();    
  13.         services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());    
  14.         services.AddDbContext<EmployeeDbContext>(o=>  
  15.         {  
  16.             o.UseSqlServer(_configuartion["connectionStrings:EmployeeDbConnectionString"]);  
  17.         });  
  18.     }    
  19.     // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.  
  20.     public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
  21.     {  
  22.         if (env.IsDevelopment())  
  23.         {  
  24.             app.UseDeveloperExceptionPage();  
  25.         }       
  26.         app.UseRouting();    
  27.         app.UseEndpoints(endpoints =>  
  28.         {  
  29.             endpoints.MapControllers();  
  30.         });  
  31.     }  
  32. }  
IEmployeeRepository.cs
  1. public interface IEmployeeRepository  
  2.     {  
  3.         IEnumerable<Employee> GetAllEmployee();  
  4.         Employee GetEmployee(int employeeId, bool isWithAddress);  
  5.         IEnumerable<Address> GetAddress(int employeeId);  
  6.         Address GetEmployeeAddress(int employeeId, int addressId);  
  7.         bool IsEmployeeAvailable(int employeeId);         
  8.     }  
EmployeeRepository.cs
  1. public class EmployeeRepository : IEmployeeRepository  
  2.     {  
  3.         private readonly EmployeeDbContext _context;  
  4.         public EmployeeRepository(EmployeeDbContext context)  
  5.         {  
  6.             _context = context;  
  7.         }    
  8.         public IEnumerable<Employee> GetAllEmployee()  
  9.         {  
  10.             return _context.Employees.OrderBy(e => e.EmployeeName).ToList();  
  11.         }    
  12.         public Employee GetEmployee(int employeeId, bool isWithAddress=false)  
  13.         {  
  14.             if (isWithAddress)  
  15.             {  
  16.                 return _context.Employees.Include(e => e.EmployeeAddress)  
  17.                             .Where(a => a.Id == employeeId).FirstOrDefault();  
  18.             }    
  19.             return _context.Employees.Where(e => e.Id==employeeId).FirstOrDefault();  
  20.         }    
  21.         public Address GetEmployeeAddress(int employeeId, int addressId)  
  22.         {  
  23.             return _context.Addresses.Where(a => a.Id == addressId  
  24.                                         && a.EmployeeId == employeeId).FirstOrDefault();  
  25.         }    
  26.         public IEnumerable<Address> GetAddress(int employeeId)  
  27.         {  
  28.             return _context.Addresses.Where(a => a.EmployeeId == employeeId).ToList();  
  29.         }    
  30.         public bool IsEmployeeAvailable(int employeeId)  
  31.         {  
  32.             return _context.Employees.Any(e => e.Id == employeeId);  
  33.         }            
  34.     }  
EmployeeModel and AddressModel
  1. public class EmployeeModel  
  2.  {  
  3.      public int EmployeeId { getset; }  
  4.      public string EmployeeName { getset; }  
  5.      public string Skill { getset; }  
  6.      public string Email { getset; }  
  7.      public ICollection<AddressModel> EmployeeAddress { getset; }  
  8.                  = new List<AddressModel>();  
  9.  }  
  10.   
  11. public class AddressModel  
  12.  {      
  13.      public int Id { getset; }  
  14.      public string AddressDetail { getset; }              
  15.  }  
Employee and Address Entities(DTO's)
  1. public class Employee  
  2.     {  
  3.         [Key]  
  4.         [DatabaseGenerated(DatabaseGeneratedOption.Identity)]  
  5.         public int Id { getset; }  
  6.         public string EmployeeName { getset; }  
  7.         public string Skill { getset; }  
  8.         public string Email { getset; }  
  9.   
  10.         public ICollection<Address> EmployeeAddress { getset; }  
  11.                     = new List<Address>();  
  12.     }  
  13.   
  14. public class Address  
  15.     {  
  16.         [Key]  
  17.         [DatabaseGenerated(DatabaseGeneratedOption.Identity)]  
  18.         public int Id { getset; }  
  19.         public string AddressDetail { getset; }  
  20.         [ForeignKey("EmployeeId")]  
  21.         public Employee Employee { getset; }  
  22.   
  23.         public int EmployeeId { getset; }  
  24.     }  
EmployeeMapper.cs
  1. public class EmployeeMapper: Profile  
  2.    {  
  3.        public EmployeeMapper()  
  4.        {  
  5.            CreateMap<Employee, EmployeeModel>();  
  6.            CreateMap<Address, AddressModel>();  
  7.        }  
  8.    }  
EmployeeController.cs
  1.    [ApiController]  
  2.    [Route("api/[controller]")]  
  3.    public class EmployeeController : ControllerBase  
  4.    {    
  5.        private readonly ILogger<EmployeeController> _logger;  
  6.        private readonly IEmployeeRepository _employeeRepository;  
  7.        private IMapper _mapper;   
  8.        public EmployeeController(ILogger<EmployeeController> logger, IEmployeeRepository employeeRepository, IMapper mapper)  
  9.        {  
  10.            _logger = logger;  
  11.            _employeeRepository = employeeRepository;  
  12.            _mapper = mapper;  
  13.        }    
  14.        // GET: api/<controller>  
  15.        [HttpGet]  
  16.        public IActionResult GetAllEmployees()  
  17.        {  
  18.            var employeeData = _employeeRepository.GetAllEmployee();    
  19.            if (employeeData == null)  
  20.            {  
  21.                return NotFound();  
  22.            }    
  23.            return Ok(_mapper.Map<IEnumerable<EmployeeModel>>(employeeData));  
  24.        }  
  25.   
  26.        [HttpGet("{id}")]  
  27.        public IActionResult GetEmployee(int id, bool isWithAddress = false)  
  28.        {  
  29.            var employee = _employeeRepository.GetEmployee(id, isWithAddress);    
  30.            if (employee == null)  
  31.            {  
  32.                return NotFound();  
  33.            }    
  34.            if (isWithAddress)  
  35.            {                  
  36.                return Ok(_mapper.Map<EmployeeModel>(employee));  
  37.            }    
  38.            return Ok(_mapper.Map<EmployeeModel>(employee));  
  39.        }  
  40.    }  
AddressController.cs
  1. [ApiController]  
  2. [Route("api/employee/{employeeId}/address")]  
  3. public class AddressController : ControllerBase  
  4. {    
  5.     private readonly ILogger<EmployeeController> _logger;  
  6.     private readonly IEmployeeRepository _employeeRepository;  
  7.     private IMapper _mapper;  
  8.     public AddressController(ILogger<EmployeeController> logger, IEmployeeRepository employeeRepository, IMapper mapper)  
  9.     {  
  10.         _logger = logger;  
  11.         _employeeRepository = employeeRepository;  
  12.         _mapper = mapper;  
  13.     }    
  14.     // GET: api/<controller>  
  15.     [HttpGet]  
  16.     public IActionResult GetAllAddress(int employeeId)  
  17.     {    
  18.         if (!_employeeRepository.IsEmployeeAvailable(employeeId))  
  19.         {  
  20.             return NotFound();  
  21.         }  
  22.         var addressData = _employeeRepository.GetAddress(employeeId);          
  23.         if (addressData == null)  
  24.         {  
  25.             return NotFound();  
  26.         }    
  27.         return Ok(_mapper.Map<IEnumerable<Address>>(addressData));  
  28.     }    
  29.   
  30.     [HttpGet("{id}", Name = "GetEmployeeAddress")]  
  31.     public IActionResult GetEmployeeAddress(int employeeId, int id)  
  32.     {  
  33.         if (!_employeeRepository.IsEmployeeAvailable(employeeId))  
  34.         {  
  35.             return NotFound();  
  36.         }    
  37.         var address = _employeeRepository.GetEmployeeAddress(employeeId, id);    
  38.         if (address == null)  
  39.         {  
  40.             return NotFound();  
  41.         }    
  42.         return Ok(_mapper.Map<Address>(address));  
  43.     }       
  44. }  

Summary

 
In this post we learned about Entity Framework core implementation in .Net Core API and complex entity - DTO mapping through AutoMapper. 
 
You can also check this article - Using Entity Framwework.


Similar Articles